• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 //#define LOG_NDEBUG 0
17 
18 #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
19 
20 #include "ExynosPrimaryDisplay.h"
21 
22 #include <linux/fb.h>
23 #include <poll.h>
24 
25 #include <chrono>
26 #include <fstream>
27 
28 #include "BrightnessController.h"
29 #include "ExynosDevice.h"
30 #include "ExynosDisplayDrmInterface.h"
31 #include "ExynosDisplayDrmInterfaceModule.h"
32 #include "ExynosExternalDisplay.h"
33 #include "ExynosHWCDebug.h"
34 #include "ExynosHWCHelper.h"
35 #include "ExynosLayer.h"
36 
37 extern struct exynos_hwc_control exynosHWCControl;
38 
39 using namespace SOC_VERSION;
40 constexpr auto nsecsPerSec = std::chrono::nanoseconds(1s).count();
41 
42 static const std::map<const DisplayType, const std::string> panelSysfsPath =
43         {{DisplayType::DISPLAY_PRIMARY, "/sys/devices/platform/exynos-drm/primary-panel/"},
44          {DisplayType::DISPLAY_SECONDARY, "/sys/devices/platform/exynos-drm/secondary-panel/"}};
45 
46 static constexpr const char *PROPERTY_BOOT_MODE = "persist.vendor.display.primary.boot_config";
47 
loadPanelGammaCalibration(const std::string & file)48 static std::string loadPanelGammaCalibration(const std::string &file) {
49     std::ifstream ifs(file);
50 
51     if (!ifs.is_open()) {
52         ALOGW("Unable to open gamma calibration '%s', error = %s", file.c_str(), strerror(errno));
53         return {};
54     }
55 
56     std::string raw_data, gamma;
57     char ch;
58     while (std::getline(ifs, raw_data, '\r')) {
59         gamma.append(raw_data);
60         gamma.append(1, ' ');
61         ifs.get(ch);
62         if (ch != '\n') {
63             gamma.append(1, ch);
64         }
65     }
66     ifs.close();
67 
68     /* eliminate space character in the last byte */
69     if (!gamma.empty()) {
70         gamma.pop_back();
71     }
72 
73     return gamma;
74 }
75 
ExynosPrimaryDisplay(uint32_t index,ExynosDevice * device)76 ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device)
77       : ExynosDisplay(index, device),
78         mMinIdleRefreshRate(0),
79         mRefreshRateDelayNanos(0),
80         mLastRefreshRateAppliedNanos(0),
81         mAppliedActiveConfig(0),
82         mDisplayIdleTimerEnabled(false),
83         mDisplayNeedHandleIdleExit(false) {
84     // TODO : Hard coded here
85     mNumMaxPriorityAllowed = 5;
86 
87     /* Initialization */
88     mType = HWC_DISPLAY_PRIMARY;
89     mIndex = index;
90     mDisplayId = getDisplayId(mType, mIndex);
91     mFramesToReachLhbmPeakBrightness =
92             property_get_int32("vendor.primarydisplay.lhbm.frames_to_reach_peak_brightness", 3);
93 
94     // Allow to enable dynamic recomposition after every power on
95     // since it will always be disabled for every power off
96     // TODO(b/268474771): to enable DR by default if video mode panel is detected
97     if (property_get_int32("vendor.display.dynamic_recomposition", 0) & (1 << index)) {
98         mDRDefault = true;
99         mDREnable = true;
100     }
101 
102     // Prepare multi resolution
103     // Will be exynosHWCControl.multiResoultion
104     mResolutionInfo.nNum = 1;
105     mResolutionInfo.nResolution[0].w = 1440;
106     mResolutionInfo.nResolution[0].h = 2960;
107     mResolutionInfo.nDSCYSliceSize[0] = 40;
108     mResolutionInfo.nDSCXSliceSize[0] = 1440 / 2;
109     mResolutionInfo.nPanelType[0] = PANEL_DSC;
110     mResolutionInfo.nResolution[1].w = 1080;
111     mResolutionInfo.nResolution[1].h = 2220;
112     mResolutionInfo.nDSCYSliceSize[1] = 30;
113     mResolutionInfo.nDSCXSliceSize[1] = 1080 / 2;
114     mResolutionInfo.nPanelType[1] = PANEL_DSC;
115     mResolutionInfo.nResolution[2].w = 720;
116     mResolutionInfo.nResolution[2].h = 1480;
117     mResolutionInfo.nDSCYSliceSize[2] = 74;
118     mResolutionInfo.nDSCXSliceSize[2] = 720;
119     mResolutionInfo.nPanelType[2] = PANEL_LEGACY;
120 
121     char value[PROPERTY_VALUE_MAX];
122     const char *earlyWakeupNodeBase = EARLY_WAKUP_NODE_0_BASE;
123     if (getDisplayTypeFromIndex(mIndex) == DisplayType::DISPLAY_SECONDARY &&
124         property_get("vendor.display.secondary_early_wakeup_node", value, "") > 0) {
125         earlyWakeupNodeBase = value;
126     }
127     mEarlyWakeupDispFd = fopen(earlyWakeupNodeBase, "w");
128     if (mEarlyWakeupDispFd == nullptr)
129         ALOGE("open %s failed! %s", earlyWakeupNodeBase, strerror(errno));
130     mBrightnessController = std::make_unique<BrightnessController>(
131             mIndex, [this]() { mDevice->onRefresh(mDisplayId); },
132             [this]() { updatePresentColorConversionInfo(); });
133 }
134 
~ExynosPrimaryDisplay()135 ExynosPrimaryDisplay::~ExynosPrimaryDisplay()
136 {
137     if (mEarlyWakeupDispFd) {
138         fclose(mEarlyWakeupDispFd);
139         mEarlyWakeupDispFd = nullptr;
140     }
141 
142     if (mDisplayNeedHandleIdleExitOfs.is_open()) {
143         mDisplayNeedHandleIdleExitOfs.close();
144     }
145 }
146 
setDDIScalerEnable(int width,int height)147 void ExynosPrimaryDisplay::setDDIScalerEnable(int width, int height) {
148 
149     if (exynosHWCControl.setDDIScaler == false) return;
150 
151     ALOGI("DDISCALER Info : setDDIScalerEnable(w=%d,h=%d)", width, height);
152     mNewScaledWidth = width;
153     mNewScaledHeight = height;
154     mXres = width;
155     mYres = height;
156 }
157 
getDDIScalerMode(int width,int height)158 int ExynosPrimaryDisplay::getDDIScalerMode(int width, int height) {
159 
160     if (exynosHWCControl.setDDIScaler == false) return 1;
161 
162     // Check if panel support support resolution or not.
163     for (uint32_t i=0; i < mResolutionInfo.nNum; i++) {
164         if (mResolutionInfo.nResolution[i].w * mResolutionInfo.nResolution[i].h ==
165                 static_cast<uint32_t>(width * height))
166             return i + 1;
167     }
168 
169     return 1; // WQHD
170 }
171 
doDisplayConfigInternal(hwc2_config_t config)172 int32_t ExynosPrimaryDisplay::doDisplayConfigInternal(hwc2_config_t config) {
173     if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON)) {
174         mPendActiveConfig = config;
175         mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_DONE;
176         DISPLAY_LOGI("%s:: Pending desired Config: %d", __func__, config);
177         return NO_ERROR;
178     }
179     return ExynosDisplay::doDisplayConfigInternal(config);
180 }
181 
getActiveConfigInternal(hwc2_config_t * outConfig)182 int32_t ExynosPrimaryDisplay::getActiveConfigInternal(hwc2_config_t *outConfig) {
183     if (outConfig && mPendActiveConfig != UINT_MAX) {
184         *outConfig = mPendActiveConfig;
185         return HWC2_ERROR_NONE;
186     }
187     return ExynosDisplay::getActiveConfigInternal(outConfig);
188 }
189 
setActiveConfigInternal(hwc2_config_t config,bool force)190 int32_t ExynosPrimaryDisplay::setActiveConfigInternal(hwc2_config_t config, bool force) {
191     hwc2_config_t cur_config;
192 
193     getActiveConfigInternal(&cur_config);
194     if (cur_config == config) {
195         ALOGI("%s:: Same display config is set", __func__);
196         return HWC2_ERROR_NONE;
197     }
198     if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON)) {
199         mPendActiveConfig = config;
200         return HWC2_ERROR_NONE;
201     }
202     return ExynosDisplay::setActiveConfigInternal(config, force);
203 }
204 
applyPendingConfig()205 int32_t ExynosPrimaryDisplay::applyPendingConfig() {
206     hwc2_config_t config;
207 
208     if (mPendActiveConfig != UINT_MAX) {
209         config = mPendActiveConfig;
210         mPendActiveConfig = UINT_MAX;
211     } else {
212         getActiveConfigInternal(&config);
213     }
214 
215     return ExynosDisplay::setActiveConfigInternal(config, true);
216 }
217 
setBootDisplayConfig(int32_t config)218 int32_t ExynosPrimaryDisplay::setBootDisplayConfig(int32_t config) {
219     auto hwcConfig = static_cast<hwc2_config_t>(config);
220 
221     const auto &it = mDisplayConfigs.find(hwcConfig);
222     if (it == mDisplayConfigs.end()) {
223         DISPLAY_LOGE("%s: invalid config %d", __func__, config);
224         return HWC2_ERROR_BAD_CONFIG;
225     }
226 
227     const auto &mode = it->second;
228     if (mode.vsyncPeriod == 0)
229         return HWC2_ERROR_BAD_CONFIG;
230 
231     int refreshRate = round(nsecsPerSec / mode.vsyncPeriod * 0.1f) * 10;
232     char modeStr[PROPERTY_VALUE_MAX];
233     int ret = snprintf(modeStr, sizeof(modeStr), "%dx%d@%d",
234              mode.width, mode.height, refreshRate);
235     if (ret <= 0)
236         return HWC2_ERROR_BAD_CONFIG;
237 
238     ALOGD("%s: mode=%s (%d) vsyncPeriod=%d", __func__, modeStr, config,
239             mode.vsyncPeriod);
240     ret = property_set(PROPERTY_BOOT_MODE, modeStr);
241 
242     return !ret ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_CONFIG;
243 }
244 
clearBootDisplayConfig()245 int32_t ExynosPrimaryDisplay::clearBootDisplayConfig() {
246     auto ret = property_set(PROPERTY_BOOT_MODE, nullptr);
247 
248     ALOGD("%s: clearing boot mode", __func__);
249     return !ret ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_CONFIG;
250 }
251 
getPreferredDisplayConfigInternal(int32_t * outConfig)252 int32_t ExynosPrimaryDisplay::getPreferredDisplayConfigInternal(int32_t *outConfig) {
253     char modeStr[PROPERTY_VALUE_MAX];
254     auto ret = property_get(PROPERTY_BOOT_MODE, modeStr, "");
255 
256     if (ret <= 0) {
257         return mDisplayInterface->getDefaultModeId(outConfig);
258     }
259 
260     int width, height;
261     int fps = 0;
262 
263     ret = sscanf(modeStr, "%dx%d@%d", &width, &height, &fps);
264     if ((ret < 3) || !fps) {
265         ALOGD("%s: unable to find boot config for mode: %s", __func__, modeStr);
266         return HWC2_ERROR_BAD_CONFIG;
267     }
268 
269     return lookupDisplayConfigs(width, height, fps, outConfig);
270 }
271 
setPowerOn()272 int32_t ExynosPrimaryDisplay::setPowerOn() {
273     ATRACE_CALL();
274     updateAppliedActiveConfig(0, 0);
275     int ret = NO_ERROR;
276     if (mDisplayId != 0 || !mFirstPowerOn) {
277         ret = applyPendingConfig();
278     }
279 
280     if (!mPowerModeState.has_value() || (*mPowerModeState == HWC2_POWER_MODE_OFF)) {
281         // check the dynamic recomposition thread by following display
282         mDevice->checkDynamicRecompositionThread();
283         if (ret) {
284             mDisplayInterface->setPowerMode(HWC2_POWER_MODE_ON);
285         }
286         setGeometryChanged(GEOMETRY_DISPLAY_POWER_ON);
287     }
288 
289     {
290         std::lock_guard<std::mutex> lock(mPowerModeMutex);
291         mPowerModeState = HWC2_POWER_MODE_ON;
292         if (mNotifyPowerOn) {
293             mPowerOnCondition.notify_one();
294             mNotifyPowerOn = false;
295         }
296     }
297 
298     if (mFirstPowerOn) {
299         firstPowerOn();
300     }
301 
302     return HWC2_ERROR_NONE;
303 }
304 
setPowerOff()305 int32_t ExynosPrimaryDisplay::setPowerOff() {
306     ATRACE_CALL();
307 
308     clearDisplay(true);
309 
310     // check the dynamic recomposition thread by following display
311     mDevice->checkDynamicRecompositionThread();
312 
313     mDisplayInterface->setPowerMode(HWC2_POWER_MODE_OFF);
314 
315     {
316         std::lock_guard<std::mutex> lock(mPowerModeMutex);
317         mPowerModeState = HWC2_POWER_MODE_OFF;
318     }
319 
320     /* It should be called from validate() when the screen is on */
321     mSkipFrame = true;
322     setGeometryChanged(GEOMETRY_DISPLAY_POWER_OFF);
323     if ((mRenderingState >= RENDERING_STATE_VALIDATED) &&
324         (mRenderingState < RENDERING_STATE_PRESENTED))
325         closeFencesForSkipFrame(RENDERING_STATE_VALIDATED);
326     mRenderingState = RENDERING_STATE_NONE;
327 
328     // in the case user turns off screen when LHBM is on
329     // TODO: b/236433238 considering a lock for mLhbmOn state
330     mLhbmOn = false;
331     return HWC2_ERROR_NONE;
332 }
333 
setPowerDoze(hwc2_power_mode_t mode)334 int32_t ExynosPrimaryDisplay::setPowerDoze(hwc2_power_mode_t mode) {
335     ATRACE_CALL();
336 
337     if (!mDisplayInterface->isDozeModeAvailable()) {
338         return HWC2_ERROR_UNSUPPORTED;
339     }
340 
341     if (mPowerModeState.has_value() &&
342         ((*mPowerModeState == HWC2_POWER_MODE_OFF) || (*mPowerModeState == HWC2_POWER_MODE_ON))) {
343         if (mDisplayInterface->setLowPowerMode()) {
344             ALOGI("Not support LP mode.");
345             return HWC2_ERROR_UNSUPPORTED;
346         }
347     }
348 
349     {
350         std::lock_guard<std::mutex> lock(mPowerModeMutex);
351         mPowerModeState = mode;
352     }
353 
354     // LHBM will be disabled in the kernel while entering AOD mode if it's
355     // already enabled. Reset the state to avoid the sync problem.
356     mBrightnessController->resetLhbmState();
357     mLhbmOn = false;
358 
359     ExynosDisplay::updateRefreshRateHint();
360 
361     return HWC2_ERROR_NONE;
362 }
363 
setPowerMode(int32_t mode)364 int32_t ExynosPrimaryDisplay::setPowerMode(int32_t mode) {
365     Mutex::Autolock lock(mDisplayMutex);
366 
367     if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::PAUSE)) {
368         mode = HWC2_POWER_MODE_OFF;
369         mPauseDisplay = true;
370     } else if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME)) {
371         mode = HWC2_POWER_MODE_ON;
372         mPauseDisplay = false;
373     }
374 
375     if (mPowerModeState.has_value() && (mode == static_cast<int32_t>(mPowerModeState.value()))) {
376         ALOGI("Skip power mode transition due to the same power state.");
377         return HWC2_ERROR_NONE;
378     }
379 
380     int fb_blank = (mode != HWC2_POWER_MODE_OFF) ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
381     ALOGD("%s:: FBIOBLANK mode(%d), blank(%d)", __func__, mode, fb_blank);
382 
383     if (fb_blank == FB_BLANK_POWERDOWN)
384         mDREnable = false;
385     else
386         mDREnable = mDRDefault;
387 
388     switch (mode) {
389         case HWC2_POWER_MODE_DOZE_SUSPEND:
390         case HWC2_POWER_MODE_DOZE:
391             return setPowerDoze(static_cast<hwc2_power_mode_t>(mode));
392         case HWC2_POWER_MODE_OFF:
393             setPowerOff();
394             break;
395         case HWC2_POWER_MODE_ON:
396             setPowerOn();
397             break;
398         default:
399             return HWC2_ERROR_BAD_PARAMETER;
400     }
401 
402     ExynosDisplay::updateRefreshRateHint();
403 
404     return HWC2_ERROR_NONE;
405 }
406 
firstPowerOn()407 void ExynosPrimaryDisplay::firstPowerOn() {
408     SetCurrentPanelGammaSource(DisplayType::DISPLAY_PRIMARY, PanelGammaSource::GAMMA_CALIBRATION);
409     mFirstPowerOn = false;
410     getDisplayIdleTimerEnabled(mDisplayIdleTimerEnabled);
411     initDisplayHandleIdleExit();
412 }
413 
getHDRException(ExynosLayer * __unused layer)414 bool ExynosPrimaryDisplay::getHDRException(ExynosLayer* __unused layer)
415 {
416     return false;
417 }
418 
initDisplayInterface(uint32_t interfaceType)419 void ExynosPrimaryDisplay::initDisplayInterface(uint32_t interfaceType)
420 {
421     if (interfaceType == INTERFACE_TYPE_DRM)
422         mDisplayInterface = std::make_unique<ExynosPrimaryDisplayDrmInterfaceModule>((ExynosDisplay *)this);
423     else
424         LOG_ALWAYS_FATAL("%s::Unknown interface type(%d)",
425                 __func__, interfaceType);
426     mDisplayInterface->init(this);
427 
428     mDpuData.init(mMaxWindowNum, mDevice->getSpecialPlaneNum(mDisplayId));
429     mLastDpuData.init(mMaxWindowNum, mDevice->getSpecialPlaneNum(mDisplayId));
430     ALOGI("window configs size(%zu) rcd configs zie(%zu)", mDpuData.configs.size(),
431           mDpuData.rcdConfigs.size());
432 }
433 
getPanelSysfsPath(const DisplayType & type)434 std::string ExynosPrimaryDisplay::getPanelSysfsPath(const DisplayType &type) {
435     if ((type < DisplayType::DISPLAY_PRIMARY) || (type >= DisplayType::DISPLAY_MAX)) {
436         ALOGE("Invalid display panel type %d", type);
437         return {};
438     }
439 
440     auto iter = panelSysfsPath.find(type);
441     if (iter == panelSysfsPath.end()) {
442         return {};
443     }
444 
445     return iter->second;
446 }
447 
SetCurrentPanelGammaSource(const DisplayType type,const PanelGammaSource & source)448 int32_t ExynosPrimaryDisplay::SetCurrentPanelGammaSource(const DisplayType type,
449                                                          const PanelGammaSource &source) {
450     std::string &&panel_sysfs_path = getPanelSysfsPath(type);
451     if (panel_sysfs_path.empty()) {
452         return HWC2_ERROR_UNSUPPORTED;
453     }
454 
455     std::ifstream ifs;
456     std::string &&path = panel_sysfs_path + "panel_name";
457     ifs.open(path, std::ifstream::in);
458     if (!ifs.is_open()) {
459         ALOGW("Unable to access panel name path '%s' (%s)", path.c_str(), strerror(errno));
460         return HWC2_ERROR_UNSUPPORTED;
461     }
462     std::string panel_name;
463     std::getline(ifs, panel_name);
464     ifs.close();
465 
466     path = panel_sysfs_path + "serial_number";
467     ifs.open(path, std::ifstream::in);
468     if (!ifs.is_open()) {
469         ALOGW("Unable to access panel id path '%s' (%s)", path.c_str(), strerror(errno));
470         return HWC2_ERROR_UNSUPPORTED;
471     }
472     std::string panel_id;
473     std::getline(ifs, panel_id);
474     ifs.close();
475 
476     std::string gamma_node = panel_sysfs_path + "gamma";
477     if (access(gamma_node.c_str(), W_OK)) {
478         ALOGW("Unable to access panel gamma calibration node '%s' (%s)", gamma_node.c_str(),
479               strerror(errno));
480         return HWC2_ERROR_UNSUPPORTED;
481     }
482 
483     std::string &&gamma_data = "default";
484     if (source == PanelGammaSource::GAMMA_CALIBRATION) {
485         std::string gamma_cal_file(kDisplayCalFilePath);
486         gamma_cal_file.append(kPanelGammaCalFilePrefix)
487                 .append(1, '_')
488                 .append(panel_name)
489                 .append(1, '_')
490                 .append(panel_id)
491                 .append(".cal");
492         if (access(gamma_cal_file.c_str(), R_OK)) {
493             ALOGI("Fail to access `%s` (%s), try golden gamma calibration", gamma_cal_file.c_str(),
494                   strerror(errno));
495             gamma_cal_file = kDisplayCalFilePath;
496             gamma_cal_file.append(kPanelGammaCalFilePrefix)
497                     .append(1, '_')
498                     .append(panel_name)
499                     .append(".cal");
500         }
501         gamma_data = loadPanelGammaCalibration(gamma_cal_file);
502     }
503 
504     if (gamma_data.empty()) {
505         return HWC2_ERROR_UNSUPPORTED;
506     }
507 
508     std::ofstream ofs(gamma_node);
509     if (!ofs.is_open()) {
510         ALOGW("Unable to open gamma node '%s', error = %s", gamma_node.c_str(), strerror(errno));
511         return HWC2_ERROR_UNSUPPORTED;
512     }
513     ofs.write(gamma_data.c_str(), gamma_data.size());
514     ofs.close();
515 
516     currentPanelGammaSource = source;
517     return HWC2_ERROR_NONE;
518 }
519 
isLhbmSupported()520 bool ExynosPrimaryDisplay::isLhbmSupported() {
521     return mBrightnessController->isLhbmSupported();
522 }
523 
524 // This function should be called by other threads (e.g. sensor HAL).
525 // HWCService can call this function but it should be for test purpose only.
setLhbmState(bool enabled)526 int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) {
527     // NOTE: mLhbmOn could be set to false at any time by setPowerOff in another
528     // thread. Make sure no side effect if that happens. Or add lock if we have
529     // to when new code is added.
530     ATRACE_CALL();
531     {
532         ATRACE_NAME("wait for power mode on");
533         std::unique_lock<std::mutex> lock(mPowerModeMutex);
534         if (mPowerModeState != HWC2_POWER_MODE_ON) {
535             mNotifyPowerOn = true;
536             if (!mPowerOnCondition.wait_for(lock, std::chrono::milliseconds(2000), [this]() {
537                     return (mPowerModeState == HWC2_POWER_MODE_ON);
538                 })) {
539                 ALOGW("%s(%d) wait for power mode on timeout !", __func__, enabled);
540                 return TIMED_OUT;
541             }
542         }
543     }
544 
545     if (enabled) {
546         ATRACE_NAME("wait for peak refresh rate");
547         std::unique_lock<std::mutex> lock(mPeakRefreshRateMutex);
548         mNotifyPeakRefreshRate = true;
549         if (!mPeakRefreshRateCondition.wait_for(lock,
550                                                 std::chrono::milliseconds(
551                                                         kLhbmWaitForPeakRefreshRateMs),
552                                                 [this]() { return isCurrentPeakRefreshRate(); })) {
553             ALOGW("setLhbmState(on) wait for peak refresh rate timeout !");
554             return TIMED_OUT;
555         }
556     }
557 
558     if (enabled) {
559         setLHBMRefreshRateThrottle(kLhbmRefreshRateThrottleMs);
560     }
561 
562     bool wasDisabled =
563             mBrightnessController
564                     ->checkSysfsStatus(BrightnessController::kLocalHbmModeFileNode,
565                                        {std::to_string(static_cast<int>(
566                                                BrightnessController::LhbmMode::DISABLED))},
567                                        0);
568     if (!enabled && wasDisabled) {
569         ALOGW("lhbm is at DISABLED state, skip disabling");
570         return NO_ERROR;
571     } else if (enabled && !wasDisabled) {
572         requestLhbm(true);
573         ALOGI("lhbm is at ENABLING or ENABLED state, re-enable to reset timeout timer");
574         return NO_ERROR;
575     }
576 
577     int64_t lhbmEnablingNanos;
578     std::vector<std::string> checkingValue = {
579             std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))};
580     if (enabled) {
581         checkingValue = {std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLING)),
582                          std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLED))};
583         lhbmEnablingNanos = systemTime(SYSTEM_TIME_MONOTONIC);
584     }
585     requestLhbm(enabled);
586     constexpr uint32_t kSysfsCheckTimeoutMs = 500;
587     ALOGI("setLhbmState =%d", enabled);
588     bool succeed =
589             mBrightnessController->checkSysfsStatus(BrightnessController::kLocalHbmModeFileNode,
590                                                     checkingValue, ms2ns(kSysfsCheckTimeoutMs));
591     if (!succeed) {
592         ALOGE("failed to update lhbm mode");
593         if (enabled) {
594             setLHBMRefreshRateThrottle(0);
595         }
596         return -ENODEV;
597     }
598 
599     if (enabled) {
600         int64_t lhbmEnablingDoneNanos = systemTime(SYSTEM_TIME_MONOTONIC);
601         bool enablingStateSupported = !mFramesToReachLhbmPeakBrightness;
602         if (enablingStateSupported) {
603             ATRACE_NAME("lhbm_wait_peak_brightness");
604             if (!mBrightnessController
605                          ->checkSysfsStatus(BrightnessController::kLocalHbmModeFileNode,
606                                             {std::to_string(static_cast<int>(
607                                                     BrightnessController::LhbmMode::ENABLED))},
608                                             ms2ns(kSysfsCheckTimeoutMs))) {
609                 ALOGE("failed to wait for lhbm becoming effective");
610                 return -EIO;
611             }
612         } else {
613             // lhbm takes effect at next vblank
614             ATRACE_NAME("lhbm_wait_apply");
615             if (mDisplayInterface->waitVBlank()) {
616                 ALOGE("%s failed to wait vblank for taking effect", __func__);
617                 return -ENODEV;
618             }
619             ATRACE_NAME("lhbm_wait_peak_brightness");
620             for (int32_t i = mFramesToReachLhbmPeakBrightness; i > 0; i--) {
621                 if (mDisplayInterface->waitVBlank()) {
622                     ALOGE("%s failed to wait vblank for peak brightness, %d", __func__, i);
623                     return -ENODEV;
624                 }
625             }
626         }
627         ALOGI("lhbm delay mode: %s, latency(ms): total: %d cmd: %d\n",
628               enablingStateSupported ? "poll" : "fixed",
629               static_cast<int>((systemTime(SYSTEM_TIME_MONOTONIC) - lhbmEnablingNanos) / 1000000),
630               static_cast<int>((lhbmEnablingDoneNanos - lhbmEnablingNanos) / 1000000));
631     } else {
632         setLHBMRefreshRateThrottle(0);
633         // lhbm takes effect at next vblank
634         ATRACE_NAME("lhbm_wait_apply");
635         if (mDisplayInterface->waitVBlank()) {
636             ALOGE("%s failed to wait vblank for taking effect", __func__);
637             return -ENODEV;
638         }
639     }
640 
641     mLhbmOn = enabled;
642     if (!mPowerModeState.has_value() || (*mPowerModeState == HWC2_POWER_MODE_OFF && mLhbmOn)) {
643         mLhbmOn = false;
644         ALOGE("%s power off during request lhbm on", __func__);
645         return -EINVAL;
646     }
647     return NO_ERROR;
648 }
649 
getLhbmState()650 bool ExynosPrimaryDisplay::getLhbmState() {
651     return mLhbmOn;
652 }
653 
setLHBMRefreshRateThrottle(const uint32_t delayMs)654 void ExynosPrimaryDisplay::setLHBMRefreshRateThrottle(const uint32_t delayMs) {
655     ATRACE_CALL();
656 
657     if (delayMs) {
658         // make new throttle take effect
659         mLastRefreshRateAppliedNanos = systemTime(SYSTEM_TIME_MONOTONIC);
660     }
661 
662     setRefreshRateThrottleNanos(std::chrono::duration_cast<std::chrono::nanoseconds>(
663                                         std::chrono::milliseconds(delayMs))
664                                         .count(),
665                                 VrrThrottleRequester::LHBM);
666 }
667 
setEarlyWakeupDisplay()668 void ExynosPrimaryDisplay::setEarlyWakeupDisplay() {
669     if (mEarlyWakeupDispFd) {
670         writeFileNode(mEarlyWakeupDispFd, 1);
671     }
672 }
673 
setExpectedPresentTime(uint64_t timestamp)674 void ExynosPrimaryDisplay::setExpectedPresentTime(uint64_t timestamp) {
675     mExpectedPresentTime.store(timestamp);
676 }
677 
getPendingExpectedPresentTime()678 uint64_t ExynosPrimaryDisplay::getPendingExpectedPresentTime() {
679     if (mExpectedPresentTime.is_dirty()) {
680         return mExpectedPresentTime.get();
681     }
682 
683     return 0;
684 }
685 
applyExpectedPresentTime()686 void ExynosPrimaryDisplay::applyExpectedPresentTime() {
687     mExpectedPresentTime.clear_dirty();
688 }
689 
setDisplayIdleTimer(const int32_t timeoutMs)690 int32_t ExynosPrimaryDisplay::setDisplayIdleTimer(const int32_t timeoutMs) {
691     bool support = false;
692     if (getDisplayIdleTimerSupport(support) || support == false) {
693         return HWC2_ERROR_UNSUPPORTED;
694     }
695 
696     if (timeoutMs < 0) {
697         return HWC2_ERROR_BAD_PARAMETER;
698     }
699 
700     if (timeoutMs > 0) {
701         setDisplayIdleDelayNanos(std::chrono::duration_cast<std::chrono::nanoseconds>(
702                                          std::chrono::milliseconds(timeoutMs))
703                                          .count(),
704                                  DispIdleTimerRequester::SF);
705     }
706 
707     bool enabled = (timeoutMs > 0);
708     if (enabled != mDisplayIdleTimerEnabled) {
709         if (setDisplayIdleTimerEnabled(enabled) == NO_ERROR) {
710             mDisplayIdleTimerEnabled = enabled;
711         }
712     }
713 
714     return HWC2_ERROR_NONE;
715 }
716 
getDisplayIdleTimerEnabled(bool & enabled)717 int32_t ExynosPrimaryDisplay::getDisplayIdleTimerEnabled(bool &enabled) {
718     bool support = false;
719     if (getDisplayIdleTimerSupport(support) || support == false) {
720         return HWC2_ERROR_UNSUPPORTED;
721     }
722 
723     const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_idle";
724     std::ifstream ifs(path);
725     if (!ifs.is_open()) {
726         ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno));
727         return errno;
728     } else {
729         std::string panel_idle;
730         std::getline(ifs, panel_idle);
731         ifs.close();
732         enabled = (panel_idle == "1");
733         ALOGI("%s() get panel_idle(%d) from the sysfs node", __func__, enabled);
734     }
735     return NO_ERROR;
736 }
737 
setDisplayIdleTimerEnabled(const bool enabled)738 int32_t ExynosPrimaryDisplay::setDisplayIdleTimerEnabled(const bool enabled) {
739     const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_idle";
740     std::ofstream ofs(path);
741     if (!ofs.is_open()) {
742         ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno));
743         return errno;
744     } else {
745         ofs << enabled;
746         ofs.close();
747         ALOGI("%s() writes panel_idle(%d) to the sysfs node", __func__, enabled);
748     }
749     return NO_ERROR;
750 }
751 
setDisplayIdleDelayNanos(const int32_t delayNanos,const DispIdleTimerRequester requester)752 int32_t ExynosPrimaryDisplay::setDisplayIdleDelayNanos(const int32_t delayNanos,
753                                                        const DispIdleTimerRequester requester) {
754     std::lock_guard<std::mutex> lock(mDisplayIdleDelayMutex);
755 
756     int64_t maxDelayNanos = 0;
757     mDisplayIdleTimerNanos[toUnderlying(requester)] = delayNanos;
758     for (uint32_t i = 0; i < toUnderlying(DispIdleTimerRequester::MAX); i++) {
759         if (mDisplayIdleTimerNanos[i] > maxDelayNanos) {
760             maxDelayNanos = mDisplayIdleTimerNanos[i];
761         }
762     }
763 
764     if (mDisplayIdleDelayNanos == maxDelayNanos) {
765         return NO_ERROR;
766     }
767 
768     mDisplayIdleDelayNanos = maxDelayNanos;
769 
770     const int32_t displayIdleDelayMs = std::chrono::duration_cast<std::chrono::milliseconds>(
771                                                std::chrono::nanoseconds(mDisplayIdleDelayNanos))
772                                                .count();
773     const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "idle_delay_ms";
774     std::ofstream ofs(path);
775     if (!ofs.is_open()) {
776         ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno));
777         return errno;
778     } else {
779         ofs << displayIdleDelayMs;
780         ALOGI("%s() writes idle_delay_ms(%d) to the sysfs node (0x%x)", __func__,
781               displayIdleDelayMs, ofs.rdstate());
782         ofs.close();
783     }
784     return NO_ERROR;
785 }
786 
initDisplayHandleIdleExit()787 void ExynosPrimaryDisplay::initDisplayHandleIdleExit() {
788     if (bool support; getDisplayIdleTimerSupport(support) || support == false) {
789         return;
790     }
791 
792     const std::string path =
793             getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_need_handle_idle_exit";
794     mDisplayNeedHandleIdleExitOfs.open(path, std::ofstream::out);
795     if (!mDisplayNeedHandleIdleExitOfs.is_open()) {
796         ALOGI("%s() '%s' doesn't exist(%s)", __func__, path.c_str(), strerror(errno));
797     }
798 
799     setDisplayNeedHandleIdleExit(false, true);
800 }
801 
setDisplayNeedHandleIdleExit(const bool needed,const bool force)802 void ExynosPrimaryDisplay::setDisplayNeedHandleIdleExit(const bool needed, const bool force) {
803     if (!mDisplayNeedHandleIdleExitOfs.is_open()) {
804         return;
805     }
806 
807     if (needed == mDisplayNeedHandleIdleExit && !force) {
808         return;
809     }
810 
811     mDisplayNeedHandleIdleExitOfs << needed;
812     if (mDisplayNeedHandleIdleExitOfs.fail()) {
813         ALOGW("%s() failed to write panel_need_handle_idle_exit(%d) to sysfs node %s", __func__,
814               needed, strerror(errno));
815         return;
816     }
817 
818     mDisplayNeedHandleIdleExitOfs.flush();
819     if (mDisplayNeedHandleIdleExitOfs.fail()) {
820         ALOGW("%s() failed to flush panel_need_handle_idle_exit(%d) to sysfs node %s", __func__,
821               needed, strerror(errno));
822         return;
823     }
824 
825     ALOGI("%s() writes panel_need_handle_idle_exit(%d) to sysfs node", __func__, needed);
826     mDisplayNeedHandleIdleExit = needed;
827 }
828 
handleDisplayIdleEnter(const uint32_t idleTeRefreshRate)829 void ExynosPrimaryDisplay::handleDisplayIdleEnter(const uint32_t idleTeRefreshRate) {
830     Mutex::Autolock lock(mDisplayMutex);
831     uint32_t btsRefreshRate = getBtsRefreshRate();
832     if (idleTeRefreshRate <= btsRefreshRate) {
833         return;
834     }
835 
836     bool needed = false;
837     for (size_t i = 0; i < mLayers.size(); i++) {
838         if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP == nullptr &&
839             !mLayers[i]->checkBtsCap(idleTeRefreshRate)) {
840             needed = true;
841             break;
842         }
843     }
844 
845     setDisplayNeedHandleIdleExit(needed, false);
846 }
847 
setMinIdleRefreshRate(const int fps)848 int ExynosPrimaryDisplay::setMinIdleRefreshRate(const int fps) {
849     mMinIdleRefreshRate = fps;
850 
851     const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "min_vrefresh";
852     std::ofstream ofs(path);
853     if (!ofs.is_open()) {
854         ALOGW("Unable to open node '%s', error = %s", path.c_str(), strerror(errno));
855         return errno;
856     } else {
857         ofs << mMinIdleRefreshRate;
858         ofs.close();
859         ALOGI("ExynosPrimaryDisplay::%s() writes min_vrefresh(%d) to the sysfs node", __func__,
860               fps);
861     }
862     return NO_ERROR;
863 }
864 
setRefreshRateThrottleNanos(const int64_t delayNanos,const VrrThrottleRequester requester)865 int ExynosPrimaryDisplay::setRefreshRateThrottleNanos(const int64_t delayNanos,
866                                                       const VrrThrottleRequester requester) {
867     ALOGI("%s() requester(%u) set delay to %" PRId64 "ns", __func__, toUnderlying(requester),
868           delayNanos);
869     if (delayNanos < 0) {
870         ALOGW("%s() set invalid delay(%" PRId64 ")", __func__, delayNanos);
871         return BAD_VALUE;
872     }
873 
874     std::lock_guard<std::mutex> lock(mIdleRefreshRateThrottleMutex);
875 
876     int64_t maxDelayNanos = 0;
877     mVrrThrottleNanos[toUnderlying(requester)] = delayNanos;
878     for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) {
879         if (mVrrThrottleNanos[i] > maxDelayNanos) {
880             maxDelayNanos = mVrrThrottleNanos[i];
881         }
882     }
883 
884     if (mRefreshRateDelayNanos == maxDelayNanos) {
885         return NO_ERROR;
886     }
887 
888     mRefreshRateDelayNanos = maxDelayNanos;
889 
890     return setDisplayIdleDelayNanos(mRefreshRateDelayNanos, DispIdleTimerRequester::VRR_THROTTLE);
891 }
892 
dump(String8 & result)893 void ExynosPrimaryDisplay::dump(String8 &result) {
894     ExynosDisplay::dump(result);
895     result.appendFormat("Display idle timer: %s\n",
896                         (mDisplayIdleTimerEnabled) ? "enabled" : "disabled");
897     for (uint32_t i = 0; i < toUnderlying(DispIdleTimerRequester::MAX); i++) {
898         result.appendFormat("\t[%u] vote to %" PRId64 " ns\n", i, mDisplayIdleTimerNanos[i]);
899     }
900     result.appendFormat("Min idle refresh rate: %d\n", mMinIdleRefreshRate);
901     result.appendFormat("Refresh rate delay: %" PRId64 " ns\n", mRefreshRateDelayNanos);
902     for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) {
903         result.appendFormat("\t[%u] vote to %" PRId64 " ns\n", i, mVrrThrottleNanos[i]);
904     }
905     result.appendFormat("\n");
906 }
907 
calculateTimeline(hwc2_config_t config,hwc_vsync_period_change_constraints_t * vsyncPeriodChangeConstraints,hwc_vsync_period_change_timeline_t * outTimeline)908 void ExynosPrimaryDisplay::calculateTimeline(
909         hwc2_config_t config, hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints,
910         hwc_vsync_period_change_timeline_t *outTimeline) {
911     int64_t desiredUpdateTime = vsyncPeriodChangeConstraints->desiredTimeNanos;
912     const int64_t origDesiredUpdateTime = desiredUpdateTime;
913     const int64_t threshold = mRefreshRateDelayNanos;
914     int64_t lastUpdateDelta = 0;
915     int64_t actualChangeTime = 0;
916     bool isDelayed = false;
917 
918     /* actualChangeTime includes transient duration */
919     mDisplayInterface->getVsyncAppliedTime(config, &actualChangeTime);
920 
921     outTimeline->refreshRequired = true;
922 
923     /* when refresh rate is from high to low */
924     if (threshold != 0 && mLastRefreshRateAppliedNanos != 0 &&
925         mDisplayConfigs[mActiveConfig].vsyncPeriod < mDisplayConfigs[config].vsyncPeriod) {
926         lastUpdateDelta = desiredUpdateTime - mLastRefreshRateAppliedNanos;
927         if (lastUpdateDelta < threshold) {
928             /* in this case, the active config change needs to be delayed */
929             isDelayed = true;
930             desiredUpdateTime += threshold - lastUpdateDelta;
931         }
932     }
933     mVsyncPeriodChangeConstraints.desiredTimeNanos = desiredUpdateTime;
934 
935     getConfigAppliedTime(mVsyncPeriodChangeConstraints.desiredTimeNanos, actualChangeTime,
936                          outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos);
937 
938     if (isDelayed) {
939         DISPLAY_LOGD(eDebugDisplayConfig,
940                      "requested config : %d(%d)->%d(%d) is delayed! "
941                      "delta %" PRId64 ", delay %" PRId64 ", threshold %" PRId64 ", "
942                      "desired %" PRId64 "->%" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64
943                      ", refreshTimeNanos:%" PRId64,
944                      mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config,
945                      mDisplayConfigs[config].vsyncPeriod, lastUpdateDelta,
946                      threshold - lastUpdateDelta, threshold, origDesiredUpdateTime,
947                      mVsyncPeriodChangeConstraints.desiredTimeNanos,
948                      outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos);
949     } else {
950         DISPLAY_LOGD(eDebugDisplayConfig,
951                      "requested config : %d(%d)->%d(%d), "
952                      "lastUpdateDelta %" PRId64 ", threshold %" PRId64 ", "
953                      "desired %" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64 "",
954                      mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config,
955                      mDisplayConfigs[config].vsyncPeriod, lastUpdateDelta, threshold,
956                      mVsyncPeriodChangeConstraints.desiredTimeNanos,
957                      outTimeline->newVsyncAppliedTimeNanos);
958     }
959 }
960 
updateAppliedActiveConfig(const hwc2_config_t newConfig,const int64_t ts)961 void ExynosPrimaryDisplay::updateAppliedActiveConfig(const hwc2_config_t newConfig,
962                                                      const int64_t ts) {
963     if (mAppliedActiveConfig == 0 ||
964         getDisplayVsyncPeriodFromConfig(mAppliedActiveConfig) !=
965                 getDisplayVsyncPeriodFromConfig(newConfig)) {
966         DISPLAY_LOGD(eDebugDisplayConfig,
967                      "%s mAppliedActiveConfig(%d->%d), mLastRefreshRateAppliedNanos(%" PRIu64
968                      " -> %" PRIu64 ")",
969                      __func__, mAppliedActiveConfig, newConfig, mLastRefreshRateAppliedNanos, ts);
970         mLastRefreshRateAppliedNanos = ts;
971     }
972 
973     mAppliedActiveConfig = newConfig;
974 }
975 
checkBtsReassignResource(const uint32_t vsyncPeriod,const uint32_t btsVsyncPeriod)976 void ExynosPrimaryDisplay::checkBtsReassignResource(const uint32_t vsyncPeriod,
977                                                     const uint32_t btsVsyncPeriod) {
978     ATRACE_CALL();
979     uint32_t refreshRate = static_cast<uint32_t>(round(nsecsPerSec / vsyncPeriod * 0.1f) * 10);
980 
981     if (vsyncPeriod < btsVsyncPeriod) {
982         for (size_t i = 0; i < mLayers.size(); i++) {
983             if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP == nullptr &&
984                 !mLayers[i]->checkBtsCap(refreshRate)) {
985                 mLayers[i]->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
986                 break;
987             }
988         }
989     } else if (vsyncPeriod > btsVsyncPeriod) {
990         for (size_t i = 0; i < mLayers.size(); i++) {
991             if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP) {
992                 float srcWidth = mLayers[i]->mSourceCrop.right - mLayers[i]->mSourceCrop.left;
993                 float srcHeight = mLayers[i]->mSourceCrop.bottom - mLayers[i]->mSourceCrop.top;
994                 float resolution = srcWidth * srcHeight * refreshRate / 1000;
995                 float ratioVertical = static_cast<float>(mLayers[i]->mDisplayFrame.bottom -
996                                                          mLayers[i]->mDisplayFrame.top) /
997                         mYres;
998 
999                 if (mLayers[i]->mOtfMPP->checkDownscaleCap(resolution, ratioVertical)) {
1000                     mLayers[i]->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED);
1001                     break;
1002                 }
1003             }
1004         }
1005     }
1006 }
1007 
isDbmSupported()1008 bool ExynosPrimaryDisplay::isDbmSupported() {
1009     return mBrightnessController->isDbmSupported();
1010 }
1011 
setDbmState(bool enabled)1012 int32_t ExynosPrimaryDisplay::setDbmState(bool enabled) {
1013     mBrightnessController->processDimBrightness(enabled);
1014     return NO_ERROR;
1015 }
1016