blob: da4017d77e7aeae0e8330186b18b48256eee8c06
1 | /* |
2 | * Copyright (c) 2018 Amlogic, Inc. All rights reserved. |
3 | * |
4 | * This source code is subject to the terms and conditions defined in the |
5 | * file 'LICENSE' which is part of this source code package. |
6 | * |
7 | * Description: |
8 | */ |
9 | |
10 | #include "VariableModeMgr.h" |
11 | |
12 | #include <HwcConfig.h> |
13 | #include <MesonLog.h> |
14 | #include <systemcontrol.h> |
15 | #include <hardware/hwcomposer2.h> |
16 | |
17 | #include <string> |
18 | |
19 | #define DEFUALT_DPI (160) |
20 | #define DEFAULT_REFRESH_RATE_60 (60.0f) |
21 | #define DEFAULT_REFRESH_RATE_50 (50.0f) |
22 | |
23 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
24 | |
25 | /* used for init default configs */ |
26 | static const drm_mode_info_t mode_info[] = { |
27 | { /* VMODE_720P */ |
28 | .name = "720p60hz", |
29 | .dpiX = DEFUALT_DPI, |
30 | .dpiY = DEFUALT_DPI, |
31 | .pixelW = 1280, |
32 | .pixelH = 720, |
33 | .refreshRate = DEFAULT_REFRESH_RATE_60, |
34 | }, |
35 | { /* VMODE_1080P */ |
36 | .name = "1080p60hz", |
37 | .dpiX = DEFUALT_DPI, |
38 | .dpiY = DEFUALT_DPI, |
39 | .pixelW = 1920, |
40 | .pixelH = 1080, |
41 | .refreshRate = DEFAULT_REFRESH_RATE_60, |
42 | }, |
43 | { /* VMODE_720P_50hz */ |
44 | .name = "720p50hz", |
45 | .dpiX = DEFUALT_DPI, |
46 | .dpiY = DEFUALT_DPI, |
47 | .pixelW = 1280, |
48 | .pixelH = 720, |
49 | .refreshRate = DEFAULT_REFRESH_RATE_50, |
50 | }, |
51 | { /* VMODE_1080P_50HZ */ |
52 | .name = "1080p50hz", |
53 | .dpiX = DEFUALT_DPI, |
54 | .dpiY = DEFUALT_DPI, |
55 | .pixelW = 1920, |
56 | .pixelH = 1080, |
57 | .refreshRate = DEFAULT_REFRESH_RATE_50, |
58 | }, |
59 | { /* DefaultMode */ |
60 | .name = "DefaultMode", |
61 | .dpiX = DEFUALT_DPI, |
62 | .dpiY = DEFUALT_DPI, |
63 | .pixelW = 1920, |
64 | .pixelH = 1080, |
65 | .refreshRate = DEFAULT_REFRESH_RATE_60, |
66 | }, |
67 | }; |
68 | |
69 | VariableModeMgr::VariableModeMgr() |
70 | : mIsInit(true) { |
71 | } |
72 | |
73 | VariableModeMgr::~VariableModeMgr() { |
74 | |
75 | } |
76 | |
77 | hwc_modes_policy_t VariableModeMgr::getPolicyType() { |
78 | return FULL_ACTIVE_POLICY; |
79 | } |
80 | |
81 | const char * VariableModeMgr::getName() { |
82 | return "VariableMode"; |
83 | } |
84 | |
85 | void VariableModeMgr::setFramebufferSize(uint32_t w, uint32_t h) { |
86 | mFbWidth = w; |
87 | mFbHeight = h; |
88 | } |
89 | |
90 | void VariableModeMgr::setDisplayResources( |
91 | std::shared_ptr<HwDisplayCrtc> & crtc, |
92 | std::shared_ptr<HwDisplayConnector> & connector) { |
93 | mConnector = connector; |
94 | mCrtc = crtc; |
95 | |
96 | /* |
97 | * Only when it is first boot will come here, |
98 | * initialize a default display mode according to the given FB size, |
99 | * and will return this default mode to SF before it calls setActiveConfig(). |
100 | */ |
101 | if (mIsInit) { |
102 | mIsInit = false; |
103 | reset(); |
104 | initDefaultDispResources(); |
105 | } |
106 | |
107 | update(); |
108 | } |
109 | |
110 | int32_t VariableModeMgr::initDefaultDispResources() { |
111 | mDefaultMode = |
112 | findMatchedMode(mFbWidth, mFbHeight, DEFAULT_REFRESH_RATE_60); |
113 | mHwcActiveModes.emplace(mHwcActiveModes.size(), mDefaultMode); |
114 | updateHwcActiveConfig(mDefaultMode.name); |
115 | MESON_LOGV("initDefaultDispResources (%s)", mDefaultMode.name); |
116 | return 0; |
117 | } |
118 | |
119 | int32_t VariableModeMgr::update() { |
120 | MESON_LOG_FUN_ENTER(); |
121 | bool useFakeMode = false; |
122 | |
123 | if (mConnector->isConnected()) { |
124 | updateHwcDispConfigs(); |
125 | drm_mode_info_t dispmode; |
126 | if (getDisplayMode(dispmode) == 0) { |
127 | updateHwcActiveConfig(dispmode.name); |
128 | } else { |
129 | useFakeMode = true; |
130 | MESON_LOGD("Get invalid display mode."); |
131 | } |
132 | } else |
133 | useFakeMode = true; |
134 | |
135 | if (useFakeMode) |
136 | updateHwcActiveConfig(mDefaultMode.name); |
137 | |
138 | MESON_LOG_FUN_LEAVE(); |
139 | return 0; |
140 | } |
141 | |
142 | int32_t VariableModeMgr::getDisplayMode(drm_mode_info_t & mode) { |
143 | return mCrtc->getMode(mode); |
144 | } |
145 | |
146 | int32_t VariableModeMgr::getDisplayConfigs( |
147 | uint32_t * outNumConfigs, uint32_t * outConfigs) { |
148 | *outNumConfigs = mHwcActiveModes.size(); |
149 | |
150 | if (outConfigs) { |
151 | updateSfDispConfigs(); |
152 | std::map<uint32_t, drm_mode_info_t>::iterator it = |
153 | mSfActiveModes.begin(); |
154 | for (uint32_t index = 0; it != mSfActiveModes.end(); ++it, ++index) { |
155 | outConfigs[index] = it->first; |
156 | MESON_LOGV("outConfig[%d]: %d.", index, outConfigs[index]); |
157 | } |
158 | } |
159 | return HWC2_ERROR_NONE; |
160 | } |
161 | |
162 | int32_t VariableModeMgr::updateHwcDispConfigs() { |
163 | std::map<uint32_t, drm_mode_info_t> activeModes; |
164 | mHwcActiveModes.clear(); |
165 | |
166 | mConnector->getModes(activeModes); |
167 | for (auto it = activeModes.begin(); it != activeModes.end(); ++it) { |
168 | // skip default / fake active mode as we add it to the end |
169 | if (!strncmp(mDefaultMode.name, it->second.name, DRM_DISPLAY_MODE_LEN) |
170 | && mDefaultMode.refreshRate == it->second.refreshRate) { |
171 | mDefaultModeSupport = true; |
172 | mDefaultMode.dpiX = it->second.dpiX; |
173 | mDefaultMode.dpiY = it->second.dpiY; |
174 | } else { |
175 | MESON_LOGV("[%s]: Hwc modes %d.", __func__, mHwcActiveModes.size()); |
176 | mHwcActiveModes.emplace(mHwcActiveModes.size(), it->second); |
177 | } |
178 | } |
179 | |
180 | // Add default mode as last, unconditionally in all cases. This is to ensure |
181 | // availability of 1080p mode always. |
182 | MESON_LOGV("[%s]: Hwc modes %d.", __func__, mHwcActiveModes.size()); |
183 | mHwcActiveModes.emplace(mHwcActiveModes.size(), mDefaultMode); |
184 | return HWC2_ERROR_NONE; |
185 | } |
186 | |
187 | int32_t VariableModeMgr::updateSfDispConfigs() { |
188 | // clear display modes |
189 | mSfActiveModes.clear(); |
190 | |
191 | mSfActiveModes = mHwcActiveModes; |
192 | |
193 | // Set active config id used by SF. |
194 | mSfActiveConfigId = mHwcActiveConfigId; |
195 | |
196 | return HWC2_ERROR_NONE; |
197 | } |
198 | |
199 | int32_t VariableModeMgr::getDisplayAttribute( |
200 | uint32_t config, int32_t attribute, int32_t * outValue, int32_t caller) { |
201 | MESON_LOGV("getDisplayAttribute: config %d, fakeConfig %d," |
202 | "HwcActiveConfig %d, SfActiveConfig %d, mExtModeSet %d, caller (%s)", |
203 | config, mFakeConfigId, mHwcActiveConfigId, mSfActiveConfigId, mExtModeSet, |
204 | caller == CALL_FROM_SF ? "SF" : "HWC"); |
205 | |
206 | std::map<uint32_t, drm_mode_info_t>::iterator it; |
207 | if (CALL_FROM_SF == caller) { |
208 | it = mSfActiveModes.find(config); |
209 | } else if (CALL_FROM_HWC == caller) { |
210 | it = mHwcActiveModes.find(config); |
211 | } |
212 | |
213 | if (it != mHwcActiveModes.end() || it != mSfActiveModes.end()) { |
214 | drm_mode_info_t curMode = it->second; |
215 | |
216 | switch (attribute) { |
217 | case HWC2_ATTRIBUTE_WIDTH: |
218 | *outValue = curMode.pixelW; |
219 | break; |
220 | case HWC2_ATTRIBUTE_HEIGHT: |
221 | *outValue = curMode.pixelH; |
222 | break; |
223 | case HWC2_ATTRIBUTE_VSYNC_PERIOD: |
224 | #ifdef HWC_HEADLESS |
225 | *outValue = 1e9 / (HWC_HEADLESS_REFRESHRATE); |
226 | #else |
227 | *outValue = 1e9 / curMode.refreshRate; |
228 | #endif |
229 | break; |
230 | case HWC2_ATTRIBUTE_DPI_X: |
231 | *outValue = curMode.dpiX * 1000.0f; |
232 | break; |
233 | case HWC2_ATTRIBUTE_DPI_Y: |
234 | *outValue = curMode.dpiY * 1000.0f; |
235 | break; |
236 | default: |
237 | MESON_LOGE("Unkown display attribute(%d)", attribute); |
238 | break; |
239 | } |
240 | |
241 | return HWC2_ERROR_NONE; |
242 | } else { |
243 | MESON_LOGE("[%s]: no support display config: %d", __func__, config); |
244 | return HWC2_ERROR_UNSUPPORTED; |
245 | } |
246 | } |
247 | |
248 | int32_t VariableModeMgr::updateHwcActiveConfig( |
249 | const char * activeMode) { |
250 | mActiveConfigStr = activeMode; |
251 | |
252 | for (auto it = mHwcActiveModes.begin(); it != mHwcActiveModes.end(); ++it) { |
253 | if (strncmp(activeMode, it->second.name, DRM_DISPLAY_MODE_LEN) == 0) { |
254 | mHwcActiveConfigId = it->first; |
255 | mFakeConfigId = mHwcActiveModes.size()-1; |
256 | MESON_LOGD("updateActiveConfig to (%s, %d)", activeMode, mHwcActiveConfigId); |
257 | return HWC2_ERROR_NONE; |
258 | } |
259 | } |
260 | |
261 | // If we reach here we are trying to set an unsupported mode. This can happen as |
262 | // SystemControl does not guarantee to keep the EDID mode list and the active |
263 | // mode id synchronised. We therefore handle the case where the active mode is |
264 | // not supported by ensuring something sane is set instead. |
265 | // NOTE: this is only really a workaround - HWC should instead guarantee that |
266 | // the display mode list and active mode reported to SF are kept in sync with |
267 | // hot plug events. |
268 | mHwcActiveConfigId = mHwcActiveModes.size()-1; |
269 | mFakeConfigId = mHwcActiveConfigId; |
270 | MESON_LOGD("updateActiveConfig something error to (%s, %d)", activeMode, mHwcActiveConfigId); |
271 | |
272 | return HWC2_ERROR_NONE; |
273 | } |
274 | |
275 | int32_t VariableModeMgr::getActiveConfig( |
276 | uint32_t * outConfig, int32_t caller) { |
277 | if (CALL_FROM_SF == caller) { |
278 | *outConfig = mExtModeSet ? mSfActiveConfigId : mFakeConfigId; |
279 | } else if (CALL_FROM_HWC == caller) { |
280 | *outConfig = mExtModeSet ? mHwcActiveConfigId : mFakeConfigId; |
281 | } |
282 | MESON_LOGV("[%s]: ret %d, Sf id %d, Hwc id %d, fake id %d, mExtModeSet %d, caller (%s)", |
283 | __func__ ,*outConfig, mSfActiveConfigId, mHwcActiveConfigId, mFakeConfigId, |
284 | mExtModeSet, caller == CALL_FROM_SF ? "SF" : "HWC"); |
285 | return HWC2_ERROR_NONE; |
286 | } |
287 | |
288 | int32_t VariableModeMgr::setActiveConfig( |
289 | uint32_t config) { |
290 | std::map<uint32_t, drm_mode_info_t>::iterator it = |
291 | mSfActiveModes.find(config); |
292 | if (it != mSfActiveModes.end()) { |
293 | drm_mode_info_t cfg = it->second; |
294 | |
295 | // update real active config. |
296 | updateHwcActiveConfig(cfg.name); |
297 | |
298 | // since SF is asking to set the mode, we should update mSFActiveConfigId |
299 | // as well here so that when SF calls getActiveConfig, we return correct |
300 | // mode. Without it, mSFActiveConfigId is getting updated only when |
301 | // updateSfDispConfigs is called by getDisplayConfigs. But getDisplayConfigs |
302 | // does not get called when user manually selects a mode and mSFActiveConfigId |
303 | // stays stale. |
304 | mSfActiveConfigId = mHwcActiveConfigId; |
305 | |
306 | // It is possible that default mode is not supported by the sink |
307 | // and it was only advertised to the FWK to force 1080p UI. |
308 | // Trap this case and do nothing. FWK will keep thinking |
309 | // 1080p is supported and set. |
310 | if (!mDefaultModeSupport |
311 | && strncmp(cfg.name, mDefaultMode.name, DRM_DISPLAY_MODE_LEN) == 0) { |
312 | MESON_LOGD("setActiveConfig default mode not supported"); |
313 | return HWC2_ERROR_NONE; |
314 | } |
315 | |
316 | mCrtc->setMode(cfg); |
317 | mExtModeSet = true; |
318 | MESON_LOGD("setActiveConfig %d, mExtModeSet %d", |
319 | config, mExtModeSet); |
320 | return HWC2_ERROR_NONE; |
321 | } else { |
322 | MESON_LOGE("set invalild active config (%d)", config); |
323 | return HWC2_ERROR_NOT_VALIDATED; |
324 | } |
325 | } |
326 | |
327 | void VariableModeMgr::reset() { |
328 | mHwcActiveModes.clear(); |
329 | mSfActiveModes.clear(); |
330 | mDefaultModeSupport = false; |
331 | mSfActiveConfigId = mHwcActiveConfigId = mFakeConfigId = -1; |
332 | mExtModeSet = false; |
333 | } |
334 | |
335 | const drm_mode_info_t VariableModeMgr::findMatchedMode( |
336 | uint32_t width, uint32_t height, float refreshrate) { |
337 | uint32_t i = 0; |
338 | uint32_t size = ARRAY_SIZE(mode_info); |
339 | for (i = 0; i < size; i++) { |
340 | if (mode_info[i].pixelW == width && |
341 | mode_info[i].pixelH == height && |
342 | mode_info[i].refreshRate == refreshrate) { |
343 | return mode_info[i]; |
344 | } |
345 | } |
346 | return mode_info[size-1]; |
347 | } |
348 | |
349 | void VariableModeMgr::dump(String8 & dumpstr) { |
350 | dumpstr.appendFormat("VariableModeMgr: %s\n", mActiveConfigStr.c_str()); |
351 | dumpstr.append("---------------------------------------------------------" |
352 | "-------------------------\n"); |
353 | dumpstr.append("| CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT |" |
354 | " DPI_X | DPI_Y |\n"); |
355 | dumpstr.append("+------------+------------------+-----------+------------+" |
356 | "-----------+-----------+\n"); |
357 | std::map<uint32_t, drm_mode_info_t>::iterator it = |
358 | mHwcActiveModes.begin(); |
359 | for (; it != mHwcActiveModes.end(); ++it) { |
360 | int mode = it->first; |
361 | drm_mode_info_t config = it->second; |
362 | dumpstr.appendFormat("%s %2d | %.3f | %5d | %5d |" |
363 | " %3d | %3d \n", |
364 | (mode == (int)mHwcActiveConfigId) ? "* " : " ", |
365 | mode, |
366 | config.refreshRate, |
367 | config.pixelW, |
368 | config.pixelH, |
369 | config.dpiX, |
370 | config.dpiY); |
371 | } |
372 | dumpstr.append("---------------------------------------------------------" |
373 | "-------------------------\n"); |
374 | } |
375 | |
376 |