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