Snap for 7584485 from af0279b3713a67b46d87416dcbe6d1a67e0b8633 to sc-d1-release

Change-Id: Ib8dde75f753ae4705f6f4009b5c7a388eb4a2a2e
diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h
index 98532ab..ae5fd30 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.h
+++ b/libhwc2.1/libdevice/ExynosDisplay.h
@@ -1163,6 +1163,9 @@
             mReqLhbm = on;
             mDevice->invalidate();
         }
+        void clearReqLhbm() { mReqLhbm = false; }
+        void setMinDisplayVsyncPeriod(uint32_t period) { mMinDisplayVsyncPeriod = period; }
+        uint32_t getMinDisplayVsyncPeriod(void) const { return mMinDisplayVsyncPeriod; }
 
     private:
         bool skipStaticLayerChanged(ExynosCompositionInfo& compositionInfo);
@@ -1189,6 +1192,9 @@
         // request lhbm state
         bool mReqLhbm = false;
 
+        // vsync period of max refresh rate
+        uint32_t mMinDisplayVsyncPeriod;
+
         /* Display hint to notify power hal */
         class PowerHalHintWorker : public Worker {
         public:
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
index 01b77af..b11f4f8 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
@@ -702,6 +702,13 @@
     // Dots per 1000 inches
     mExynosDisplay->mYdpi = mm_height ? (mDozeDrmMode.v_display() * kUmPerInch) / mm_height : -1;
 
+    // force to turn off lhbm
+    if (mBrightnessCtrl.LhbmOn.get() == true) {
+        mExynosDisplay->clearReqLhbm();
+        mExynosDisplay->updateBrightnessState();
+        mLhbmForceUpdated = true;
+    }
+
     return setActiveDrmMode(mDozeDrmMode);
 }
 
@@ -794,6 +801,7 @@
         /* key: (width<<32 | height) */
         std::map<uint64_t, uint32_t> groupIds;
         uint32_t groupId = 0;
+        uint32_t min_vsync_period = UINT_MAX;
 
         for (const DrmMode &mode : mDrmConnector->modes()) {
             displayConfigs_t configs;
@@ -813,11 +821,14 @@
             configs.Xdpi = mm_width ? (mode.h_display() * kUmPerInch) / mm_width : -1;
             // Dots per 1000 inches
             configs.Ydpi = mm_height ? (mode.v_display() * kUmPerInch) / mm_height : -1;
+            // find min vsync period
+            if (configs.vsyncPeriod <= min_vsync_period) min_vsync_period = configs.vsyncPeriod;
             mExynosDisplay->mDisplayConfigs.insert(std::make_pair(mode.id(), configs));
             ALOGD("config group(%d), w(%d), h(%d), vsync(%d), xdpi(%d), ydpi(%d)",
                     configs.groupId, configs.width, configs.height,
                     configs.vsyncPeriod, configs.Xdpi, configs.Ydpi);
         }
+        mExynosDisplay->setMinDisplayVsyncPeriod(min_vsync_period);
     }
 
     uint32_t num_modes = static_cast<uint32_t>(mDrmConnector->modes().size());
@@ -1036,6 +1047,18 @@
 
     DrmModeAtomicReq drmReq(this);
 
+    if (mLhbmForceUpdated) {
+        if (mBrightnessCtrl.LhbmOn.is_dirty()) {
+            if ((ret = drmReq.atomicAddProperty(mDrmConnector->id(), mDrmConnector->lhbm_on(),
+                                                mBrightnessCtrl.LhbmOn.get())) < 0) {
+                HWC_LOGE(mExynosDisplay, "%s: Fail to set lhbm_on property", __func__);
+            }
+            mBrightnessCtrl.LhbmOn.clear_dirty();
+            mExynosDisplay->notifyLhbmState(mBrightnessCtrl.LhbmOn.get());
+        }
+        mLhbmForceUpdated = false;
+    }
+
     if ((ret = setDisplayMode(drmReq, modeBlob)) != NO_ERROR) {
         drmReq.addOldBlob(modeBlob);
         HWC_LOGE(mExynosDisplay, "%s: Fail to apply display mode",
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
index f1f85ea..8356238 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
@@ -483,6 +483,7 @@
         static constexpr int32_t kHbmDimmingTimeUs = 5000000;
 
         FramebufferManager mFBManager;
+        bool mLhbmForceUpdated = false;
 
         /*
          * BrightnessDimmingUsage:
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
index c69388c..f911206 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
@@ -441,7 +441,28 @@
     return HWC2_ERROR_NONE;
 }
 
+bool ExynosPrimaryDisplay::isLhbmSwitchAvailable(bool enabled) {
+    Mutex::Autolock lock(mDisplayMutex);
+    if ((mPowerModeState != HWC2_POWER_MODE_ON) && enabled) {
+        ALOGW("skip LHBM, not ON state ");
+        return false;
+    }
+
+    if (mVsyncPeriod != getMinDisplayVsyncPeriod()) {
+        if (enabled) {
+            ALOGW("skip LHBM on, not max refresh rate");
+            return false;
+        }
+        ALOGW("calling setLhbmState in refresh rate=%d", mVsyncPeriod);
+    }
+    return true;
+}
+
 int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
+    if (mLhbmOn == enabled) return NO_ERROR;
+
+    if (!isLhbmSwitchAvailable(enabled)) return INVALID_OPERATION;
+
     requestLhbm(enabled);
     ALOGI("setLhbmState =%d", enabled);
 
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
index c49ae5e..f61b492 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h
@@ -85,6 +85,7 @@
                 "/sys/class/backlight/panel0-backlight/local_hbm_mode";
         std::mutex lhbm_mutex_;
         std::condition_variable lhbm_cond_;
+        bool isLhbmSwitchAvailable(bool enabled);
 
         FILE* mWakeupDispFd;
         static constexpr const char* kWakeupDispFilePath =
diff --git a/libhwc2.1/pixel-display.cpp b/libhwc2.1/pixel-display.cpp
index b6d0eb3..617718d 100644
--- a/libhwc2.1/pixel-display.cpp
+++ b/libhwc2.1/pixel-display.cpp
@@ -122,6 +122,8 @@
             return ndk::ScopedAStatus::ok();
         else if (ret == TIMED_OUT)
             return ndk::ScopedAStatus::fromExceptionCode(STATUS_TIMED_OUT);
+        else if (ret == INVALID_OPERATION)
+            return ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
     }
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }