1 /*
2  * Copyright (C) 2024 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 
17 #include "DisplayTe2Manager.h"
18 
DisplayTe2Manager(ExynosDisplay * display,int32_t panelIndex,int fixedTe2DefaultRateHz)19 DisplayTe2Manager::DisplayTe2Manager(ExynosDisplay* display, int32_t panelIndex,
20                                      int fixedTe2DefaultRateHz)
21       : mDisplay(display),
22         mPanelIndex(panelIndex),
23         mMinRefreshRateForFixedTe2(0),
24         mFixedTe2RateHz(fixedTe2DefaultRateHz),
25         mIsOptionFixedTe2(true),
26         mRefreshRateChangeListenerRegistered(false),
27         mPendingOptionChangeableTe2(false),
28         mPendingFixedTe2Rate(0) {}
29 
setTe2Option(bool fixedTe2)30 void DisplayTe2Manager::setTe2Option(bool fixedTe2) {
31     int32_t ret = writeIntToFile(getPanelTe2OptionPath(), fixedTe2);
32     if (!ret) {
33         ALOGI("DisplayTe2Manager::%s writes te2_option(%d) to the sysfs node", __func__, fixedTe2);
34         mIsOptionFixedTe2 = fixedTe2;
35         if (fixedTe2) {
36             setFixedTe2RateInternal(mFixedTe2RateHz, true);
37         } else if (!mRefreshRateChangeListenerRegistered) {
38             // register listener for changeable TE2
39             if (!mDisplay) {
40                 ALOGW("DisplayTe2Manager::%s unable to register refresh rate change listener",
41                       __func__);
42             } else if (!mDisplay->registerRefreshRateChangeListener(
43                                static_cast<std::shared_ptr<RefreshRateChangeListener>>(this))) {
44                 mRefreshRateChangeListenerRegistered = true;
45             } else {
46                 ALOGW("DisplayTe2Manager::%s failed to register refresh rate change listener",
47                       __func__);
48             }
49         }
50     } else {
51         ALOGW("DisplayTe2Manager::%s failed to write te2_option(%d) to the sysfs node", __func__,
52               fixedTe2);
53     }
54 }
55 
setTe2Rate(int targetTe2RateHz)56 int32_t DisplayTe2Manager::setTe2Rate(int targetTe2RateHz) {
57     int32_t ret = writeIntToFile(getPanelTe2RatePath(), targetTe2RateHz);
58     if (!ret) {
59         ALOGI("DisplayTe2Manager::%s writes te2_rate_hz(%d) to the sysfs node", __func__,
60               targetTe2RateHz);
61     } else {
62         ALOGW("DisplayTe2Manager::%s failed to write te2_rate_hz(%d) to the sysfs node", __func__,
63               targetTe2RateHz);
64     }
65     return ret;
66 }
67 
setFixedTe2Rate(int targetTe2RateHz)68 int32_t DisplayTe2Manager::setFixedTe2Rate(int targetTe2RateHz) {
69     Mutex::Autolock lock(mTe2Mutex);
70     return setFixedTe2RateInternal(targetTe2RateHz, false);
71 }
72 
setFixedTe2RateInternal(int targetTe2RateHz,bool enforce)73 int32_t DisplayTe2Manager::setFixedTe2RateInternal(int targetTe2RateHz, bool enforce) {
74     if (!mIsOptionFixedTe2) {
75         ALOGW("DisplayTe2Manager::%s current option is not fixed TE2", __func__);
76         return -EINVAL;
77     }
78     if (targetTe2RateHz == mFixedTe2RateHz && !enforce) {
79         return NO_ERROR;
80     } else {
81         int32_t ret = setTe2Rate(targetTe2RateHz);
82         if (!ret) mFixedTe2RateHz = targetTe2RateHz;
83         return ret;
84     }
85 }
86 
setChangeableTe2Rate(int targetTe2RateHz)87 int32_t DisplayTe2Manager::setChangeableTe2Rate(int targetTe2RateHz) {
88     if (mIsOptionFixedTe2) {
89         ALOGW("DisplayTe2Manager::%s current option is not changeable", __func__);
90         return -EINVAL;
91     }
92     if (!mDisplay) {
93         ALOGW("DisplayTe2Manager::%s unable to get peak refresh rate", __func__);
94         return -EINVAL;
95     }
96 
97     // While the proximity sensor is active, changeable TE2 should be used. In this case, it
98     // should have the tolerance to receive only min (idle) and target (active) notifications of
99     // refresh rate changes and ignore the intermediate values.
100     if (targetTe2RateHz == mMinRefreshRateForFixedTe2 ||
101         targetTe2RateHz == mDisplay->getRefreshRate(mDisplay->mActiveConfig)) {
102         return setTe2Rate(targetTe2RateHz);
103     } else {
104         return NO_ERROR;
105     }
106 }
107 
updateTe2OptionForProximity(bool proximityActive,int minRefreshRate,bool dozeMode)108 void DisplayTe2Manager::updateTe2OptionForProximity(bool proximityActive, int minRefreshRate,
109                                                     bool dozeMode) {
110     Mutex::Autolock lock(mTe2Mutex);
111     bool isOptionFixed = (!proximityActive || (proximityActive && dozeMode));
112     // update the min refresh rate for changeable TE2 usage
113     if (minRefreshRate) mMinRefreshRateForFixedTe2 = minRefreshRate;
114     if (proximityActive && dozeMode) mPendingOptionChangeableTe2 = true;
115     if (isOptionFixed == mIsOptionFixedTe2) return;
116 
117     setTe2Option(isOptionFixed);
118 }
119 
updateTe2ForDozeMode()120 void DisplayTe2Manager::updateTe2ForDozeMode() {
121     Mutex::Autolock lock(mTe2Mutex);
122     mPendingFixedTe2Rate = mFixedTe2RateHz;
123     mFixedTe2RateHz = kFixedTe2RateForDozeMode;
124 
125     if (!mIsOptionFixedTe2) {
126         mPendingOptionChangeableTe2 = true;
127         setTe2Option(true);
128     }
129 }
130 
restoreTe2FromDozeMode()131 void DisplayTe2Manager::restoreTe2FromDozeMode() {
132     Mutex::Autolock lock(mTe2Mutex);
133     if (mPendingFixedTe2Rate) mFixedTe2RateHz = mPendingFixedTe2Rate;
134 
135     if (mPendingOptionChangeableTe2) {
136         setTe2Option(false);
137         mPendingOptionChangeableTe2 = false;
138     }
139 }
140 
onRefreshRateChange(int refreshRate)141 void DisplayTe2Manager::onRefreshRateChange(int refreshRate) {
142     Mutex::Autolock lock(mTe2Mutex);
143     if (!mIsOptionFixedTe2 && refreshRate) setChangeableTe2Rate(refreshRate);
144 }
145 
dump(String8 & result) const146 void DisplayTe2Manager::dump(String8& result) const {
147     result.appendFormat("DisplayTe2Manager:\n");
148     result.appendFormat("\tmin refresh rate for fixed TE2: %d\n", mMinRefreshRateForFixedTe2);
149     if (!mIsOptionFixedTe2) {
150         result.appendFormat("\tcurrent TE2: changeable\n");
151     } else {
152         result.appendFormat("\tcurrent TE2: fixed %d Hz\n", mFixedTe2RateHz);
153     }
154     result.appendFormat("\n");
155 }
156