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 #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
18 
19 #include "DisplayTe2Manager.h"
20 
DisplayTe2Manager(ExynosDisplay * display,int32_t panelIndex,int fixedTe2DefaultRateHz)21 DisplayTe2Manager::DisplayTe2Manager(ExynosDisplay* display, int32_t panelIndex,
22                                      int fixedTe2DefaultRateHz)
23       : mDisplay(display),
24         mPanelIndex(panelIndex),
25         mMinRefreshRateForFixedTe2(0),
26         mFixedTe2RateHz(fixedTe2DefaultRateHz),
27         mIsOptionFixedTe2(true),
28         mRefreshRateChangeListenerRegistered(false),
29         mPendingOptionChangeableTe2(false),
30         mPendingFixedTe2Rate(0) {
31     mProximitySensorStateNotifierWorker =
32             std::make_unique<ProximitySensorStateNotifierWorker>(this);
33 }
34 
setTe2Option(bool fixedTe2)35 void DisplayTe2Manager::setTe2Option(bool fixedTe2) {
36     int32_t ret = writeIntToFile(getPanelTe2OptionPath(), fixedTe2);
37     if (!ret) {
38         ALOGI("DisplayTe2Manager::%s writes te2_option(%d) to the sysfs node", __func__, fixedTe2);
39         mIsOptionFixedTe2 = fixedTe2;
40         if (fixedTe2) {
41             setFixedTe2RateInternal(mFixedTe2RateHz, true);
42         } else if (!mRefreshRateChangeListenerRegistered) {
43             // register listener for changeable TE2
44             if (!mDisplay) {
45                 ALOGW("DisplayTe2Manager::%s unable to register refresh rate change listener",
46                       __func__);
47             } else if (!mDisplay->registerRefreshRateChangeListener(
48                                static_cast<std::shared_ptr<RefreshRateChangeListener>>(this))) {
49                 mRefreshRateChangeListenerRegistered = true;
50             } else {
51                 ALOGW("DisplayTe2Manager::%s failed to register refresh rate change listener",
52                       __func__);
53             }
54         }
55     } else {
56         ALOGW("DisplayTe2Manager::%s failed to write te2_option(%d) to the sysfs node", __func__,
57               fixedTe2);
58     }
59 }
60 
setTe2Rate(int targetTe2RateHz)61 int32_t DisplayTe2Manager::setTe2Rate(int targetTe2RateHz) {
62     int32_t ret = writeIntToFile(getPanelTe2RatePath(), targetTe2RateHz);
63     if (!ret) {
64         ALOGI("DisplayTe2Manager::%s writes te2_rate_hz(%d) to the sysfs node", __func__,
65               targetTe2RateHz);
66     } else {
67         ALOGW("DisplayTe2Manager::%s failed to write te2_rate_hz(%d) to the sysfs node", __func__,
68               targetTe2RateHz);
69     }
70     return ret;
71 }
72 
setFixedTe2Rate(int targetTe2RateHz)73 int32_t DisplayTe2Manager::setFixedTe2Rate(int targetTe2RateHz) {
74     Mutex::Autolock lock(mTe2Mutex);
75     return setFixedTe2RateInternal(targetTe2RateHz, false);
76 }
77 
setFixedTe2RateInternal(int targetTe2RateHz,bool enforce)78 int32_t DisplayTe2Manager::setFixedTe2RateInternal(int targetTe2RateHz, bool enforce) {
79     if (!mIsOptionFixedTe2) {
80         ALOGW("DisplayTe2Manager::%s current option is not fixed TE2", __func__);
81         return -EINVAL;
82     }
83     if (targetTe2RateHz == mFixedTe2RateHz && !enforce) {
84         return NO_ERROR;
85     } else {
86         int32_t ret = setTe2Rate(targetTe2RateHz);
87         if (!ret) mFixedTe2RateHz = targetTe2RateHz;
88         return ret;
89     }
90 }
91 
setChangeableTe2Rate(int targetTe2RateHz)92 int32_t DisplayTe2Manager::setChangeableTe2Rate(int targetTe2RateHz) {
93     if (mIsOptionFixedTe2) {
94         ALOGW("DisplayTe2Manager::%s current option is not changeable", __func__);
95         return -EINVAL;
96     }
97     if (!mDisplay) {
98         ALOGW("DisplayTe2Manager::%s unable to get peak refresh rate", __func__);
99         return -EINVAL;
100     }
101 
102     // While the proximity sensor is active, changeable TE2 should be used. In this case, it
103     // should have the tolerance to receive only min (idle) and target (active) notifications of
104     // refresh rate changes and ignore the intermediate values.
105     if (targetTe2RateHz == mMinRefreshRateForFixedTe2 ||
106         targetTe2RateHz == mDisplay->getRefreshRate(mDisplay->mActiveConfig)) {
107         return setTe2Rate(targetTe2RateHz);
108     } else {
109         return NO_ERROR;
110     }
111 }
112 
updateTe2OptionForProximity(bool proximityActive,int minRefreshRate,bool dozeMode)113 void DisplayTe2Manager::updateTe2OptionForProximity(bool proximityActive, int minRefreshRate,
114                                                     bool dozeMode) {
115     Mutex::Autolock lock(mTe2Mutex);
116     bool isOptionFixed = (!proximityActive || (proximityActive && dozeMode));
117     // update the min refresh rate for changeable TE2 usage
118     if (minRefreshRate) mMinRefreshRateForFixedTe2 = minRefreshRate;
119     if (proximityActive && dozeMode) mPendingOptionChangeableTe2 = true;
120     if (isOptionFixed == mIsOptionFixedTe2) return;
121 
122     setTe2Option(isOptionFixed);
123 }
124 
updateTe2ForDozeMode()125 void DisplayTe2Manager::updateTe2ForDozeMode() {
126     Mutex::Autolock lock(mTe2Mutex);
127     mPendingFixedTe2Rate = mFixedTe2RateHz;
128     mFixedTe2RateHz = kFixedTe2RateForDozeMode;
129 
130     if (!mIsOptionFixedTe2) {
131         mPendingOptionChangeableTe2 = true;
132         setTe2Option(true);
133     }
134 }
135 
restoreTe2FromDozeMode()136 void DisplayTe2Manager::restoreTe2FromDozeMode() {
137     Mutex::Autolock lock(mTe2Mutex);
138     if (mPendingFixedTe2Rate) mFixedTe2RateHz = mPendingFixedTe2Rate;
139 
140     if (mPendingOptionChangeableTe2) {
141         setTe2Option(false);
142         mPendingOptionChangeableTe2 = false;
143     }
144 }
145 
onRefreshRateChange(int refreshRate)146 void DisplayTe2Manager::onRefreshRateChange(int refreshRate) {
147     Mutex::Autolock lock(mTe2Mutex);
148     if (!mIsOptionFixedTe2 && refreshRate) setChangeableTe2Rate(refreshRate);
149 }
150 
handleProximitySensorStateChange(bool active)151 void DisplayTe2Manager::handleProximitySensorStateChange(bool active) {
152     if (mProximitySensorStateNotifierWorker) {
153         mProximitySensorStateNotifierWorker->onStateChanged(active);
154     } else {
155         ALOGW("DisplayTe2Manager::%s unable to handle the state change", __func__);
156     }
157 }
158 
dump(String8 & result) const159 void DisplayTe2Manager::dump(String8& result) const {
160     result.appendFormat("DisplayTe2Manager:\n");
161     result.appendFormat("\tmin refresh rate for fixed TE2: %d\n", mMinRefreshRateForFixedTe2);
162     if (!mIsOptionFixedTe2) {
163         result.appendFormat("\tcurrent TE2: changeable\n");
164     } else {
165         result.appendFormat("\tcurrent TE2: fixed %d Hz\n", mFixedTe2RateHz);
166     }
167     result.appendFormat("\n");
168 }
169 
ProximitySensorStateNotifierWorker(DisplayTe2Manager * te2Manager)170 DisplayTe2Manager::ProximitySensorStateNotifierWorker::ProximitySensorStateNotifierWorker(
171         DisplayTe2Manager* te2Manager)
172       : Worker("ProximitySensorStateNotifierWorker", HAL_PRIORITY_URGENT_DISPLAY),
173         mTe2Manager(te2Manager),
174         mIsStateActive(false),
175         mReceivedFirstStateAfterTimeout(false),
176         mPendingState(ProximitySensorState::NONE) {
177     InitWorker();
178 }
179 
~ProximitySensorStateNotifierWorker()180 DisplayTe2Manager::ProximitySensorStateNotifierWorker::~ProximitySensorStateNotifierWorker() {
181     Exit();
182 }
183 
onStateChanged(bool active)184 void DisplayTe2Manager::ProximitySensorStateNotifierWorker::onStateChanged(bool active) {
185     ATRACE_INT("proximitySensorState(HAL)", active);
186     Lock();
187     mIsStateActive = active;
188     Unlock();
189     Signal();
190 }
191 
Routine()192 void DisplayTe2Manager::ProximitySensorStateNotifierWorker::Routine() {
193     ATRACE_NAME("StateNotifierWorker");
194     int ret;
195     Lock();
196     ret = WaitForSignalOrExitLocked(ms2ns(kDebounceTimeMs));
197     if (ret == -EINTR) {
198         ALOGE("ProximitySensorStateNotifierWorker: failed to wait for signal");
199         mReceivedFirstStateAfterTimeout = false;
200         Unlock();
201         return;
202     }
203 
204     if (!mReceivedFirstStateAfterTimeout) {
205         if (ret != -ETIMEDOUT) {
206             // the 1st signal after timeout, send the notification immediately
207             ALOGI("ProximitySensorStateNotifierWorker: %s: notify state (%d)", __func__,
208                   mIsStateActive);
209             mTe2Manager->mDisplay->onProximitySensorStateChanged(mIsStateActive);
210             mReceivedFirstStateAfterTimeout = true;
211         }
212     } else {
213         if (ret != -ETIMEDOUT) {
214             if (!mIsStateActive) {
215                 // inactive within kDebounceTimeMs, update the pending state
216                 mPendingState = ProximitySensorState::INACTIVE;
217             } else {
218                 // notify immediately if active
219                 ALOGI("ProximitySensorStateNotifierWorker: %s: notify state (1)", __func__);
220                 mTe2Manager->mDisplay->onProximitySensorStateChanged(true);
221                 mPendingState = ProximitySensorState::NONE;
222             }
223         } else {
224             // no signal within kDebounceTimeMs, notify the pending state if it exists
225             if (mPendingState != ProximitySensorState::NONE) {
226                 mIsStateActive = (mPendingState == ProximitySensorState::ACTIVE);
227                 ALOGI("ProximitySensorStateNotifierWorker: %s: notify pending state (%d)", __func__,
228                       mIsStateActive);
229                 mTe2Manager->mDisplay->onProximitySensorStateChanged(mIsStateActive);
230                 mPendingState = ProximitySensorState::NONE;
231             } else {
232                 mReceivedFirstStateAfterTimeout = false;
233             }
234         }
235         ATRACE_INT("proximitySensorPendingState", static_cast<uint32_t>(mPendingState));
236     }
237     Unlock();
238 }
239