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