Merge "common: Do not enable QTI_BSP flag" into display.lnx.3.0-dev
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 1470223..3415ac6 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
+* Copyright (c) 2013-2014, 2016, 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
@@ -253,6 +253,7 @@
             dpyattr.xdpi = outParcel.readFloat();
             dpyattr.ydpi = outParcel.readFloat();
             dpyattr.panel_type = (char) outParcel.readInt32();
+            dpyattr.is_yuv = outParcel.readInt32();
             ALOGI("%s() Received attrs for index %d: xres %d, yres %d",
                     __FUNCTION__, configIndex, dpyattr.xres, dpyattr.yres);
         } else {
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 05a7f29..15aba94 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -85,8 +85,9 @@
     float xdpi;
     float ydpi;
     char panel_type;
+    bool is_yuv;
     DisplayAttributes() : vsync_period(0), xres(0), yres(0), xdpi(0.0f),
-            ydpi(0.0f), panel_type(0) {}
+            ydpi(0.0f), panel_type(0), is_yuv(false) {}
 } DisplayAttributes_t;
 
 //=============================================================================
diff --git a/libqdutils/qdMetaData.cpp b/libqdutils/qdMetaData.cpp
index 79daa14..72edfdf 100644
--- a/libqdutils/qdMetaData.cpp
+++ b/libqdutils/qdMetaData.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2016, 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
@@ -67,7 +67,7 @@
             data->bufferDim = *((BufferDim_t *)param);
             break;
         case UPDATE_REFRESH_RATE:
-            data->refreshrate = *((uint32_t *)param);
+            data->refreshrate = *((float *)param);
             break;
         case UPDATE_COLOR_SPACE:
             data->colorSpace = *((ColorSpace_t *)param);
@@ -96,3 +96,106 @@
                                                                         errno);
     return 0;
 }
+
+int getMetaData(private_handle_t *handle, DispFetchParamType paramType,
+                                                    void *param) {
+    if (!handle) {
+        ALOGE("%s: Private handle is null!", __func__);
+        return -1;
+    }
+    if (handle->fd_metadata == -1) {
+        ALOGE("%s: Bad fd for extra data!", __func__);
+        return -1;
+    }
+    if (!param) {
+        ALOGE("%s: input param is null!", __func__);
+        return -1;
+    }
+    unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+    void *base = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED,
+        handle->fd_metadata, 0);
+    if (base == reinterpret_cast<void*>(MAP_FAILED)) {
+        ALOGE("%s: mmap() failed: error is %s!", __func__, strerror(errno));
+        return -1;
+    }
+
+    MetaData_t *data = reinterpret_cast <MetaData_t *>(base);
+    data->operation |= paramType;
+    switch (paramType) {
+        case GET_PP_PARAM_INTERLACED:
+            *((int32_t *)param) = data->interlaced;
+            break;
+        case GET_BUFFER_GEOMETRY:
+            *((BufferDim_t *)param) = data->bufferDim;
+            break;
+        case GET_REFRESH_RATE:
+            *((float *)param) = data->refreshrate;
+            break;
+        case GET_COLOR_SPACE:
+            *((ColorSpace_t *)param) = data->colorSpace;
+            break;
+        case GET_MAP_SECURE_BUFFER:
+            *((int32_t *)param) = data->mapSecureBuffer;
+            break;
+        case GET_S3D_FORMAT:
+            *((uint32_t *)param) = data->s3dFormat;
+            break;
+        case GET_LINEAR_FORMAT:
+            *((uint32_t *)param) = data->linearFormat;
+            break;
+        case GET_IGC:
+            *((IGC_t *)param) = data->igc;
+            break;
+        case GET_SINGLE_BUFFER_MODE:
+            *((uint32_t *)param) = data->isSingleBufferMode ;
+            break;
+        default:
+            ALOGE("Unknown paramType %d", paramType);
+            break;
+    }
+    if(munmap(base, size))
+        ALOGE("%s: failed to unmap ptr %p, err %d", __func__, (void*)base,
+                                                                        errno);
+    return 0;
+}
+
+int copyMetaData(struct private_handle_t *src, struct private_handle_t *dst) {
+    if (!src || !dst) {
+        ALOGE("%s: Private handle is null!", __func__);
+        return -1;
+    }
+    if (src->fd_metadata == -1) {
+        ALOGE("%s: Bad fd for src extra data!", __func__);
+        return -1;
+    }
+    if (dst->fd_metadata == -1) {
+        ALOGE("%s: Bad fd for dst extra data!", __func__);
+        return -1;
+    }
+
+    unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+
+    void *base_src = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED,
+        src->fd_metadata, 0);
+    if (base_src == reinterpret_cast<void*>(MAP_FAILED)) {
+        ALOGE("%s: src mmap() failed: error is %s!", __func__, strerror(errno));
+        return -1;
+    }
+
+    void *base_dst = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED,
+        dst->fd_metadata, 0);
+    if (base_dst == reinterpret_cast<void*>(MAP_FAILED)) {
+        ALOGE("%s: dst mmap() failed: error is %s!", __func__, strerror(errno));
+        return -1;
+    }
+
+    memcpy(base_dst, base_src, size);
+
+    if(munmap(base_src, size))
+        ALOGE("%s: failed to unmap src ptr %p, err %d", __func__, (void*)base_src,
+                                                                        errno);
+    if(munmap(base_dst, size))
+        ALOGE("%s: failed to unmap src ptr %p, err %d", __func__, (void*)base_dst,
+                                                                        errno);
+    return 0;
+}
diff --git a/libqdutils/qdMetaData.h b/libqdutils/qdMetaData.h
index a1d9350..fd4f444 100644
--- a/libqdutils/qdMetaData.h
+++ b/libqdutils/qdMetaData.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2016, 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
@@ -61,7 +61,7 @@
     int32_t operation;
     int32_t interlaced;
     struct BufferDim_t bufferDim;
-    uint32_t refreshrate;
+    float refreshrate;
     enum ColorSpace_t colorSpace;
     enum IGC_t igc;
      /* Gralloc sets PRIV_SECURE_BUFFER flag to inform that the buffers are from
@@ -99,10 +99,26 @@
     SET_SINGLE_BUFFER_MODE = 0x4000,
 };
 
+enum DispFetchParamType {
+    GET_PP_PARAM_INTERLACED = 0x0004,
+    GET_BUFFER_GEOMETRY = 0x0080,
+    GET_REFRESH_RATE = 0x0100,
+    GET_COLOR_SPACE = 0x0200,
+    GET_MAP_SECURE_BUFFER = 0x400,
+    GET_S3D_FORMAT = 0x800,
+    GET_LINEAR_FORMAT = 0x1000,
+    GET_IGC = 0x2000,
+    GET_SINGLE_BUFFER_MODE = 0x4000,
+};
+
 struct private_handle_t;
 int setMetaData(struct private_handle_t *handle, enum DispParamType paramType,
         void *param);
 
+int getMetaData(struct private_handle_t *handle, enum DispFetchParamType paramType,
+        void *param);
+
+int copyMetaData(struct private_handle_t *src, struct private_handle_t *dst);
 #ifdef __cplusplus
 }
 #endif
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index a74b34b..adb1851 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -96,6 +96,7 @@
   float y_dpi = 0.0f;             //!< Dots per inch in Y-direction.
   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.
 };
 
 /*! @brief Event data associated with VSync event.
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 38ccf21..bc5361c 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -455,7 +455,8 @@
             (vsync_period_ns != attributes.vsync_period_ns) ||
             (v_front_porch != attributes.v_front_porch) ||
             (v_back_porch != attributes.v_back_porch) ||
-            (v_pulse_width != attributes.v_pulse_width));
+            (v_pulse_width != attributes.v_pulse_width) ||
+            (is_yuv != attributes.is_yuv));
   }
 
   bool operator ==(const HWDisplayAttributes &attributes) {
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 33ee08d..5df06f6 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -52,10 +52,9 @@
   hw_panel_info_ = HWPanelInfo();
   hw_intf_->GetHWPanelInfo(&hw_panel_info_);
 
-  HWDisplayAttributes display_attrib;
   uint32_t active_index = 0;
   hw_intf_->GetActiveConfig(&active_index);
-  hw_intf_->GetDisplayAttributes(active_index, &display_attrib);
+  hw_intf_->GetDisplayAttributes(active_index, &display_attributes_);
 
   HWScaleLutInfo lut_info = {};
   error = comp_manager_->GetScaleLutConfig(&lut_info);
@@ -67,7 +66,7 @@
     goto CleanupOnError;
   }
 
-  error = comp_manager_->RegisterDisplay(display_type_, display_attrib,
+  error = comp_manager_->RegisterDisplay(display_type_, display_attributes_,
                                          hw_panel_info_, &display_comp_ctx_);
   if (error != kErrorNone) {
     goto CleanupOnError;
@@ -92,7 +91,7 @@
   }
 
   color_mgr_ = ColorManagerProxy::CreateColorManagerProxy(display_type_, hw_intf_,
-                               display_attrib, hw_panel_info_);
+                               display_attributes_, hw_panel_info_);
   if (!color_mgr_) {
     DLOGW("Unable to create ColorManagerProxy for display = %d", display_type_);
   }
@@ -202,6 +201,10 @@
     }
   }
 
+  if (one_frame_full_roi_) {
+    ControlPartialUpdate(false, &pending);
+  }
+
   // Clean hw layers for reuse.
   hw_layers_ = HWLayers();
   hw_layers_.info.stack = layer_stack;
@@ -245,6 +248,11 @@
     ControlPartialUpdate(true, &pending);
   }
 
+  if (one_frame_full_roi_) {
+    ControlPartialUpdate(true, &pending);
+    one_frame_full_roi_ = false;
+  }
+
   return error;
 }
 
@@ -467,6 +475,8 @@
     return error;
   }
 
+  hw_intf_->GetHWPanelInfo(&hw_panel_info_);
+
   if (display_comp_ctx_) {
     comp_manager_->UnregisterDisplay(display_comp_ctx_);
   }
@@ -474,6 +484,10 @@
   error = comp_manager_->RegisterDisplay(display_type_, attrib, hw_panel_info_,
                                          &display_comp_ctx_);
 
+  if (error == kErrorNone && partial_update_control_) {
+    one_frame_full_roi_ = true;
+  }
+
   return error;
 }
 
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 7242156..c290e96 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -89,6 +89,7 @@
   HWDeviceType hw_device_type_;
   HWInterface *hw_intf_ = NULL;
   HWPanelInfo hw_panel_info_;
+  HWDisplayAttributes display_attributes_;
   BufferSyncHandler *buffer_sync_handler_ = NULL;
   CompManager *comp_manager_ = NULL;
   RotatorInterface *rotator_intf_ = NULL;
@@ -108,6 +109,7 @@
   HWEventsInterface *hw_events_intf_ = NULL;
 
  private:
+  bool one_frame_full_roi_ = false;
   // Unused
   virtual DisplayError GetConfig(DisplayConfigFixedInfo *variable_info) {
     return kErrorNone;
diff --git a/sdm/libs/core/display_hdmi.cpp b/sdm/libs/core/display_hdmi.cpp
index 6522377..9a9628a 100644
--- a/sdm/libs/core/display_hdmi.cpp
+++ b/sdm/libs/core/display_hdmi.cpp
@@ -190,12 +190,31 @@
 DisplayError DisplayHDMI::GetRefreshRateRange(uint32_t *min_refresh_rate,
                                               uint32_t *max_refresh_rate) {
   SCOPE_LOCK(locker_);
-  return DisplayBase::GetRefreshRateRange(min_refresh_rate, max_refresh_rate);
+  DisplayError error = kErrorNone;
+
+  if (hw_panel_info_.min_fps && hw_panel_info_.max_fps) {
+    *min_refresh_rate = hw_panel_info_.min_fps;
+    *max_refresh_rate = hw_panel_info_.max_fps;
+  } else {
+    error = DisplayBase::GetRefreshRateRange(min_refresh_rate, max_refresh_rate);
+  }
+
+  return error;
 }
 
 DisplayError DisplayHDMI::SetRefreshRate(uint32_t refresh_rate) {
   SCOPE_LOCK(locker_);
-  return kErrorNotSupported;
+
+  if (!active_) {
+    return kErrorPermission;
+  }
+
+  DisplayError error = hw_intf_->SetRefreshRate(refresh_rate);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  return kErrorNone;
 }
 
 bool DisplayHDMI::IsUnderscanSupported() {
@@ -358,9 +377,10 @@
   hw_intf_->GetActiveConfig(&active_index);
   hw_intf_->GetDisplayAttributes(active_index, &display_attributes);
 
-  if (panel_info != hw_panel_info_) {
+  if (panel_info != hw_panel_info_ || display_attributes != display_attributes_) {
     comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes, panel_info);
     hw_panel_info_ = panel_info;
+    display_attributes_ = display_attributes;
   }
 }
 
diff --git a/sdm/libs/core/fb/hw_hdmi.cpp b/sdm/libs/core/fb/hw_hdmi.cpp
index 73a6a3c..db7a2d9 100644
--- a/sdm/libs/core/fb/hw_hdmi.cpp
+++ b/sdm/libs/core/fb/hw_hdmi.cpp
@@ -260,6 +260,7 @@
   }
 
   GetDisplayS3DSupport(index, display_attributes);
+  display_attributes->is_yuv = IS_BIT_SET(timing_mode->pixel_formats, 1);
 
   return kErrorNone;
 }
@@ -317,6 +318,8 @@
 
   active_config_index_ = index;
 
+  frame_rate_ = timing_mode->refresh_rate;
+
   // Get the supported s3d modes for current active config index
   HWDisplayAttributes attrib;
   GetDisplayS3DSupport(index, &attrib);
@@ -696,5 +699,61 @@
   return kErrorNone;
 }
 
+DisplayError HWHDMI::SetRefreshRate(uint32_t refresh_rate) {
+  char mode_path[kMaxStringLength] = {0};
+  char node_path[kMaxStringLength] = {0};
+  uint32_t mode = kModeHFP;
+
+  if (refresh_rate == frame_rate_) {
+    return kErrorNone;
+  }
+
+  snprintf(mode_path, sizeof(mode_path), "%s%d/msm_fb_dfps_mode", fb_path_, fb_node_index_);
+  snprintf(node_path, sizeof(node_path), "%s%d/dynamic_fps", fb_path_, fb_node_index_);
+
+  int fd_mode = Sys::open_(mode_path, O_WRONLY);
+  if (fd_mode < 0) {
+    DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
+    return kErrorFileDescriptor;
+  }
+
+  char dfps_mode[kMaxStringLength];
+  snprintf(dfps_mode, sizeof(dfps_mode), "%d", mode);
+  DLOGI_IF(kTagDriverConfig, "Setting dfps_mode  = %d", mode);
+  ssize_t len = Sys::pwrite_(fd_mode, dfps_mode, strlen(dfps_mode), 0);
+  if (len < 0) {
+    DLOGE("Failed to enable dfps mode %d with error %s", mode, strerror(errno));
+    Sys::close_(fd_mode);
+    return kErrorUndefined;
+  }
+  Sys::close_(fd_mode);
+
+  int fd_node = Sys::open_(node_path, O_WRONLY);
+  if (fd_node < 0) {
+    DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
+    return kErrorFileDescriptor;
+  }
+
+  char refresh_rate_string[kMaxStringLength];
+  snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", refresh_rate);
+  DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", refresh_rate);
+  len = Sys::pwrite_(fd_node, refresh_rate_string, strlen(refresh_rate_string), 0);
+  if (len < 0) {
+    DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
+    Sys::close_(fd_node);
+    return kErrorUndefined;
+  }
+  Sys::close_(fd_node);
+
+  DisplayError error = ReadTimingInfo();
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  frame_rate_ = refresh_rate;
+
+  return kErrorNone;
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/core/fb/hw_hdmi.h b/sdm/libs/core/fb/hw_hdmi.h
index 50bbbaa..aa5e2a0 100644
--- a/sdm/libs/core/fb/hw_hdmi.h
+++ b/sdm/libs/core/fb/hw_hdmi.h
@@ -40,6 +40,18 @@
   static DisplayError Destroy(HWInterface *intf);
 
  protected:
+  enum HWFramerateUpdate {
+    // Switch framerate by switch to other standard modes though panel blank/unblank
+    kModeSuspendResume,
+    // Switch framerate by tuning pixel clock
+    kModeClock,
+    // Switch framerate by tuning vertical front porch
+    kModeVFP,
+    // Switch framerate by tuning horizontal front porch
+    kModeHFP,
+    kModeMAX
+  };
+
   HWHDMI(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf);
   virtual DisplayError Init();
   virtual DisplayError Deinit();
@@ -56,6 +68,7 @@
   virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
   virtual DisplayError Validate(HWLayers *hw_layers);
   virtual DisplayError SetS3DMode(HWS3DMode s3d_mode);
+  virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
 
  private:
   DisplayError ReadEDIDInfo();
@@ -80,6 +93,7 @@
   std::map<HWS3DMode, msm_hdmi_s3d_mode> s3d_mode_sdm_to_mdp_;
   std::vector<HWS3DMode> supported_s3d_modes_;
   int active_mdp_s3d_mode_ = HDMI_S3D_NONE;
+  uint32_t frame_rate_ = 0;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index ab9b4a7..29e0c1a 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -537,11 +537,7 @@
       layer_stack_.flags.cursor_present = true;
     }
 
-    if (layer->frame_rate > metadata_refresh_rate_) {
-      metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate);
-    } else {
-      layer->frame_rate = current_refresh_rate_;
-    }
+    PrepareDynamicRefreshRate(layer);
 
     layer->input_buffer->buffer_id = reinterpret_cast<uint64_t>(hwc_layer.handle);
   }
@@ -1314,21 +1310,6 @@
   }
 }
 
-uint32_t HWCDisplay::RoundToStandardFPS(uint32_t fps) {
-  static const uint32_t standard_fps[4] = {30, 24, 48, 60};
-
-  int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0]));
-  for (int i = 0; i < count; i++) {
-    if ((standard_fps[i] - fps) < 2) {
-      // Most likely used for video, the fps can fluctuate
-      // Ex: b/w 29 and 30 for 30 fps clip
-      return standard_fps[i];
-    }
-  }
-
-  return fps;
-}
-
 void HWCDisplay::ApplyScanAdjustment(hwc_rect_t *display_frame) {
 }
 
@@ -1510,6 +1491,35 @@
   return (updating_count == 1);
 }
 
+bool HWCDisplay::SingleVideoLayerUpdating(uint32_t app_layer_count) {
+  uint32_t updating_count = 0;
+
+  for (uint i = 0; i < app_layer_count; i++) {
+    Layer *layer = layer_stack_.layers[i];
+    if (layer->flags.updating && (layer->input_buffer->flags.video == true)) {
+      updating_count++;
+    }
+  }
+
+  return (updating_count == 1);
+}
+
+uint32_t HWCDisplay::RoundToStandardFPS(float fps) {
+  static const uint32_t standard_fps[4] = {30, 24, 48, 60};
+  uint32_t frame_rate = (uint32_t)(fps);
+
+  int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0]));
+  for (int i = 0; i < count; i++) {
+    if ((standard_fps[i] - frame_rate) < 2) {
+      // Most likely used for video, the fps can fluctuate
+      // Ex: b/w 29 and 30 for 30 fps clip
+      return standard_fps[i];
+    }
+  }
+
+  return frame_rate;
+}
+
 uint32_t HWCDisplay::SanitizeRefreshRate(uint32_t req_refresh_rate) {
   uint32_t refresh_rate = req_refresh_rate;
 
@@ -1530,4 +1540,12 @@
   return display_class_;
 }
 
+void HWCDisplay::PrepareDynamicRefreshRate(Layer *layer) {
+  if (layer->frame_rate > metadata_refresh_rate_) {
+    metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate);
+  } else {
+    layer->frame_rate = current_refresh_rate_;
+  }
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index 7b14f10..17db165 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -149,6 +149,9 @@
   virtual int CommitLayerStack(hwc_display_contents_1_t *content_list);
   virtual int PostCommitLayerStack(hwc_display_contents_1_t *content_list);
   virtual void DumpOutputBuffer(const BufferInfo& buffer_info, void *base, int fence);
+  virtual uint32_t RoundToStandardFPS(float fps);
+  virtual uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate);
+  virtual void PrepareDynamicRefreshRate(Layer *layer);
   inline void SetRect(const hwc_rect_t &source, LayerRect *target);
   inline void SetRect(const hwc_frect_t &source, LayerRect *target);
   inline void SetComposition(const int32_t &source, LayerComposition *target);
@@ -160,7 +163,6 @@
   const char *GetDisplayString();
   void ScaleDisplayFrame(hwc_rect_t *display_frame);
   void MarkLayersForGPUBypass(hwc_display_contents_1_t *content_list);
-  uint32_t RoundToStandardFPS(uint32_t fps);
   virtual void ApplyScanAdjustment(hwc_rect_t *display_frame);
   DisplayError SetCSC(ColorSpace_t source, LayerCSC *target);
   DisplayError SetIGC(IGC_t source, LayerIGC *target);
@@ -169,7 +171,7 @@
   void CacheLayerStackInfo(hwc_display_contents_1_t *content_list);
   bool IsLayerUpdating(hwc_display_contents_1_t *content_list, int layer_index);
   bool SingleLayerUpdating(uint32_t app_layer_count);
-  uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate);
+  bool SingleVideoLayerUpdating(uint32_t app_layer_count);
 
   enum {
     INPUT_LAYER_DUMP,
diff --git a/sdm/libs/hwc/hwc_display_external.cpp b/sdm/libs/hwc/hwc_display_external.cpp
index 813b123..a647517 100644
--- a/sdm/libs/hwc/hwc_display_external.cpp
+++ b/sdm/libs/hwc/hwc_display_external.cpp
@@ -49,6 +49,7 @@
                                HWCDisplay **hwc_display) {
   uint32_t external_width = 0;
   uint32_t external_height = 0;
+  int drc_enabled = 0;
 
   HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, hwc_procs, qservice);
   int status = hwc_display_external->Init();
@@ -80,6 +81,9 @@
     return status;
   }
 
+  HWCDebugHandler::Get()->GetProperty("sdm.hdmi.drc_enabled", &(drc_enabled));
+  reinterpret_cast<HWCDisplayExternal *>(hwc_display_external)->drc_enabled_ = drc_enabled;
+
   *hwc_display = hwc_display_external;
 
   return status;
@@ -98,6 +102,7 @@
 
 int HWCDisplayExternal::Prepare(hwc_display_contents_1_t *content_list) {
   int status = 0;
+  DisplayError error = kErrorNone;
 
   if (secure_display_active_) {
     MarkLayersForGPUBypass(content_list);
@@ -119,6 +124,18 @@
     return 0;
   }
 
+  bool one_video_updating_layer = SingleVideoLayerUpdating(UINT32(content_list->numHwLayers - 1));
+
+  if (current_refresh_rate_ != metadata_refresh_rate_ && one_video_updating_layer && drc_enabled_) {
+    error = display_intf_->SetRefreshRate(metadata_refresh_rate_);
+  }
+
+  if (error == kErrorNone) {
+    // On success, set current refresh rate to new refresh rate
+    current_refresh_rate_ = metadata_refresh_rate_;
+  }
+
+
   status = PrepareLayerStack(content_list);
   if (status) {
     return status;
@@ -221,5 +238,36 @@
   }
 }
 
+uint32_t HWCDisplayExternal::RoundToStandardFPS(float fps) {
+  static const uint32_t standard_fps[] = {23976, 24000, 25000, 29970, 30000, 50000, 59940, 60000};
+  static const uint32_t mapping_fps[] = {59940, 60000, 60000, 59940, 60000, 50000, 59940, 60000};
+  uint32_t frame_rate = (uint32_t)(fps * 1000);
+
+  int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0]));
+  for (int i = 0; i < count; i++) {
+    // Most likely used for video, the fps for frames should be stable from video side.
+    if (standard_fps[i] > frame_rate) {
+      if (i > 0) {
+        if ((standard_fps[i] - frame_rate) > (frame_rate - standard_fps[i-1])) {
+          return mapping_fps[i-1];
+        } else {
+          return mapping_fps[i];
+        }
+      } else {
+        return mapping_fps[i];
+      }
+    }
+  }
+
+  return standard_fps[count - 1];
+}
+
+void HWCDisplayExternal::PrepareDynamicRefreshRate(Layer *layer) {
+  if (layer->input_buffer->flags.video) {
+    metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate);
+    layer->frame_rate = current_refresh_rate_;
+  }
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/hwc/hwc_display_external.h b/sdm/libs/hwc/hwc_display_external.h
index 436190d..c54f738 100644
--- a/sdm/libs/hwc/hwc_display_external.h
+++ b/sdm/libs/hwc/hwc_display_external.h
@@ -41,6 +41,11 @@
   virtual int Commit(hwc_display_contents_1_t *content_list);
   virtual void SetSecureDisplay(bool secure_display_active);
 
+ protected:
+  virtual uint32_t RoundToStandardFPS(float fps);
+  virtual void PrepareDynamicRefreshRate(Layer *layer);
+  int drc_enabled_ = 0;
+
  private:
   HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs,
                      qService::QService *qservice);
diff --git a/sdm/libs/hwc/hwc_session.cpp b/sdm/libs/hwc/hwc_session.cpp
index 7928765..9632d71 100644
--- a/sdm/libs/hwc/hwc_session.cpp
+++ b/sdm/libs/hwc/hwc_session.cpp
@@ -939,6 +939,7 @@
       output_parcel->writeFloat(attributes.x_dpi);
       output_parcel->writeFloat(attributes.y_dpi);
       output_parcel->writeInt32(0);  // Panel type, unsupported.
+      output_parcel->writeInt32(attributes.is_yuv);
     }
   }