blob: 2d6cf78203c9ed614ceb480eb51459f92d2d1402
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 "ActiveModeMgr.h" |
11 | #include <HwcConfig.h> |
12 | #include <MesonLog.h> |
13 | #include <systemcontrol.h> |
14 | #include <hardware/hwcomposer2.h> |
15 | |
16 | #include <string> |
17 | #include <math.h> |
18 | |
19 | |
20 | #define DEFUALT_DPI (160) |
21 | #define DEFAULT_REFRESH_RATE_60 (60.0f) |
22 | #define DEFAULT_REFRESH_RATE_50 (50.0f) |
23 | |
24 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
25 | |
26 | /* used for init default configs */ |
27 | static const drm_mode_info_t mode_info[] = { |
28 | { /* VMODE_720P */ |
29 | .name = "720p60hz", |
30 | .dpiX = DEFUALT_DPI, |
31 | .dpiY = DEFUALT_DPI, |
32 | .pixelW = 1280, |
33 | .pixelH = 720, |
34 | .refreshRate = DEFAULT_REFRESH_RATE_60, |
35 | }, |
36 | { /* VMODE_1080P */ |
37 | .name = "1080p60hz", |
38 | .dpiX = DEFUALT_DPI, |
39 | .dpiY = DEFUALT_DPI, |
40 | .pixelW = 1920, |
41 | .pixelH = 1080, |
42 | .refreshRate = DEFAULT_REFRESH_RATE_60, |
43 | }, |
44 | { /* VMODE_720P_50hz */ |
45 | .name = "720p50hz", |
46 | .dpiX = DEFUALT_DPI, |
47 | .dpiY = DEFUALT_DPI, |
48 | .pixelW = 1280, |
49 | .pixelH = 720, |
50 | .refreshRate = DEFAULT_REFRESH_RATE_50, |
51 | }, |
52 | { /* VMODE_1080P_50HZ */ |
53 | .name = "1080p50hz", |
54 | .dpiX = DEFUALT_DPI, |
55 | .dpiY = DEFUALT_DPI, |
56 | .pixelW = 1920, |
57 | .pixelH = 1080, |
58 | .refreshRate = DEFAULT_REFRESH_RATE_50, |
59 | }, |
60 | { /* DefaultMode */ |
61 | .name = "DefaultMode", |
62 | .dpiX = DEFUALT_DPI, |
63 | .dpiY = DEFUALT_DPI, |
64 | .pixelW = 1920, |
65 | .pixelH = 1080, |
66 | .refreshRate = DEFAULT_REFRESH_RATE_60, |
67 | }, |
68 | }; |
69 | |
70 | ActiveModeMgr::ActiveModeMgr() |
71 | : mIsInit(true) { |
72 | } |
73 | |
74 | ActiveModeMgr::~ActiveModeMgr() { |
75 | |
76 | } |
77 | |
78 | hwc_modes_policy_t ActiveModeMgr::getPolicyType() { |
79 | return ACTIVE_MODE_POLICY; |
80 | } |
81 | |
82 | const char * ActiveModeMgr::getName() { |
83 | return "ActiveMode"; |
84 | } |
85 | |
86 | void ActiveModeMgr::setFramebufferSize(uint32_t w, uint32_t h) { |
87 | mFbWidth = w; |
88 | mFbHeight = h; |
89 | } |
90 | |
91 | void ActiveModeMgr::setDisplayResources( |
92 | std::shared_ptr<HwDisplayCrtc> & crtc, |
93 | std::shared_ptr<HwDisplayConnector> & connector) { |
94 | mConnector = connector; |
95 | mCrtc = crtc; |
96 | |
97 | /* |
98 | * Only when it is first boot will come here, |
99 | * initialize a default display mode according to the given FB size, |
100 | * and will return this default mode to SF before it calls setActiveConfig(). |
101 | */ |
102 | if (mIsInit) { |
103 | mIsInit = false; |
104 | reset(); |
105 | initDefaultDispResources(); |
106 | } |
107 | } |
108 | |
109 | int32_t ActiveModeMgr::initDefaultDispResources() { |
110 | mDefaultMode = |
111 | findMatchedMode(mFbWidth, mFbHeight, DEFAULT_REFRESH_RATE_60); |
112 | mHwcActiveModes.emplace(mHwcActiveModes.size(), mDefaultMode); |
113 | updateHwcActiveConfig(mDefaultMode.name); |
114 | MESON_LOGV("initDefaultDispResources (%s)", mDefaultMode.name); |
115 | return 0; |
116 | } |
117 | |
118 | int32_t ActiveModeMgr::update() { |
119 | MESON_LOG_FUN_ENTER(); |
120 | useFakeMode = false; |
121 | if (mConnector->isConnected()) { |
122 | //buidl config lists for hwc and sf |
123 | drm_mode_info_t dispmode; |
124 | int32_t rnt; |
125 | rnt = getDisplayMode(dispmode); |
126 | MESON_LOGD("ActiveModeMgr::update() dispmode.name [%s] mExtModeSet:%d rnt %d", dispmode.name, mExtModeSet, rnt); |
127 | if (rnt == 0) { |
128 | if (!mExtModeSet) { |
129 | updateHwcDispConfigs(); |
130 | updateSfDispConfigs(); |
131 | } |
132 | } else { |
133 | useFakeMode = true; |
134 | MESON_LOGD("Get invalid display mode."); |
135 | } |
136 | } else |
137 | useFakeMode = true; |
138 | |
139 | if (useFakeMode) |
140 | updateHwcActiveConfig(mDefaultMode.name); |
141 | |
142 | MESON_LOG_FUN_LEAVE(); |
143 | return 0; |
144 | } |
145 | |
146 | int32_t ActiveModeMgr::getDisplayMode(drm_mode_info_t & mode) { |
147 | return mCrtc->getMode(mode); |
148 | } |
149 | |
150 | int32_t ActiveModeMgr::getDisplayConfigs( |
151 | uint32_t * outNumConfigs, uint32_t * outConfigs) { |
152 | *outNumConfigs = mSfActiveModes.size(); |
153 | MESON_LOGD("ActiveModeMgr::getDisplayConfigs(a,b)"); |
154 | if (outConfigs) { |
155 | updateSfDispConfigs(); |
156 | std::map<uint32_t, drm_mode_info_t>::iterator it = |
157 | mSfActiveModes.begin(); |
158 | for (uint32_t index = 0; it != mSfActiveModes.end(); ++it, ++index) { |
159 | outConfigs[index] = it->first; |
160 | MESON_LOGV("outConfig[%d]: %d.", index, outConfigs[index]); |
161 | } |
162 | } |
163 | return HWC2_ERROR_NONE; |
164 | } |
165 | |
166 | |
167 | bool ActiveModeMgr::isFracRate(float refreshRate) { |
168 | return refreshRate > floor(refreshRate) ? true : false; |
169 | } |
170 | |
171 | int32_t ActiveModeMgr::updateHwcDispConfigs() { |
172 | std::map<uint32_t, drm_mode_info_t> supportedModes; |
173 | drm_mode_info_t activeMode; |
174 | mHwcActiveModes.clear(); |
175 | mHwcActiveConfigId = -1; |
176 | MESON_LOGD("ActiveModeMgr::updateHwcDispConfigs()"); |
177 | |
178 | mConnector->getModes(supportedModes); |
179 | if (mCrtc->getMode(activeMode) != 0) { |
180 | activeMode = mDefaultMode; |
181 | } |
182 | mActiveConfigStr = activeMode.name; |
183 | |
184 | for (auto it = supportedModes.begin(); it != supportedModes.end(); ++it) { |
185 | MESON_LOGV("[%s]: add Hwc modes %s.", __func__, it->second.name); |
186 | mHwcActiveModes.emplace(mHwcActiveModes.size(), it->second); |
187 | |
188 | if (!strncmp(activeMode.name, it->second.name, DRM_DISPLAY_MODE_LEN) && |
189 | activeMode.refreshRate == it->second.refreshRate) { |
190 | mHwcActiveConfigId = mHwcActiveModes.size() - 1; |
191 | mActiveConfigStr = activeMode.name; |
192 | } |
193 | } |
194 | |
195 | mConnector->setMode(activeMode); |
196 | |
197 | if (mHwcActiveModes.empty()) { |
198 | mHwcActiveModes.emplace(mHwcActiveModes.size(), mDefaultMode); |
199 | mHwcActiveConfigId = mHwcActiveModes.size() - 1; |
200 | } |
201 | |
202 | MESON_LOGD("[%s]: updateHwcDispConfigs Hwc active modes %s. refreshRate %f", |
203 | __func__, activeMode.name, activeMode.refreshRate); |
204 | return HWC2_ERROR_NONE; |
205 | } |
206 | |
207 | int32_t ActiveModeMgr::updateSfDispConfigs() { |
208 | // clear display modes |
209 | mSfActiveModes.clear(); |
210 | mSfActiveConfigId = -1; |
211 | |
212 | std::map<uint32_t, drm_mode_info_t> mTmpModes; |
213 | mTmpModes = mHwcActiveModes; |
214 | |
215 | MESON_LOGD("ActiveModeMgr::updateSfDispConfigs()"); |
216 | |
217 | std::map<float, drm_mode_info_t> tmpList; |
218 | std::map<float, drm_mode_info_t>::iterator tmpIt; |
219 | |
220 | for (auto it = mTmpModes.begin(); it != mTmpModes.end(); ++it) { |
221 | //first check the fps, if there is not the same fps, add it to sf list |
222 | //then check the width, add the biggest width one. |
223 | drm_mode_info_t cfg = it->second; |
224 | std::string cMode = cfg.name; |
225 | float cFps = cfg.refreshRate; |
226 | uint32_t cWidth = cfg.pixelW; |
227 | |
228 | tmpIt = tmpList.find(cFps); |
229 | if (tmpIt != tmpList.end()) { |
230 | drm_mode_info_t iCfg = tmpIt->second; |
231 | uint32_t iWidth = iCfg.pixelW; |
232 | if ((cWidth >= iWidth) && (cWidth != 4096)) { |
233 | tmpList.erase(tmpIt); |
234 | tmpList.emplace(cFps, it->second); |
235 | } |
236 | } else { |
237 | tmpList.emplace(cFps, it->second); |
238 | } |
239 | } |
240 | |
241 | for (tmpIt = tmpList.begin(); tmpIt != tmpList.end(); ++tmpIt) { |
242 | mSfActiveModes.emplace(mSfActiveModes.size(), tmpIt->second); |
243 | |
244 | auto it = mHwcActiveModes.find(mHwcActiveConfigId); |
245 | if (it != mHwcActiveModes.end()) { |
246 | if (!strncmp(it->second.name, tmpIt->second.name, DRM_DISPLAY_MODE_LEN) |
247 | && it->second.refreshRate == tmpIt->second.refreshRate) { |
248 | mSfActiveConfigId = mSfActiveModes.size() - 1; |
249 | MESON_LOGD("curMode: %s", mActiveConfigStr.c_str()); |
250 | } |
251 | } |
252 | } |
253 | |
254 | MESON_LOGD("update Sf list with no default mode done, size (%zu)", mSfActiveModes.size()); |
255 | |
256 | mFakeConfigId = mSfActiveConfigId; |
257 | return HWC2_ERROR_NONE; |
258 | } |
259 | |
260 | int32_t ActiveModeMgr::getDisplayAttribute( |
261 | uint32_t config, int32_t attribute, int32_t * outValue, int32_t caller __unused) { |
262 | /* MESON_LOGV("getDisplayAttribute: config %d, fakeConfig %d," |
263 | "HwcActiveConfig %d, SfActiveConfig %d, mExtModeSet %d, caller (%s)", |
264 | config, mFakeConfigId, mHwcActiveConfigId, mSfActiveConfigId, mExtModeSet, |
265 | caller == CALL_FROM_SF ? "SF" : "HWC");*/ |
266 | |
267 | std::map<uint32_t, drm_mode_info_t>::iterator it; |
268 | it = mSfActiveModes.find(config); |
269 | if (it != mSfActiveModes.end()) { |
270 | drm_mode_info_t curMode = it->second; |
271 | switch (attribute) { |
272 | case HWC2_ATTRIBUTE_WIDTH: |
273 | *outValue = mDefaultMode.pixelW; |
274 | break; |
275 | case HWC2_ATTRIBUTE_HEIGHT: |
276 | *outValue = mDefaultMode.pixelH; |
277 | break; |
278 | case HWC2_ATTRIBUTE_VSYNC_PERIOD: |
279 | #ifdef HWC_HEADLESS |
280 | *outValue = 1e9 / (HWC_HEADLESS_REFRESHRATE); |
281 | #else |
282 | *outValue = 1e9 / curMode.refreshRate; |
283 | #endif |
284 | break; |
285 | case HWC2_ATTRIBUTE_DPI_X: |
286 | *outValue = curMode.dpiX * 1000.0f; |
287 | break; |
288 | case HWC2_ATTRIBUTE_DPI_Y: |
289 | *outValue = curMode.dpiY * 1000.0f; |
290 | break; |
291 | default: |
292 | MESON_LOGE("Unkown display attribute(%d)", attribute); |
293 | break; |
294 | } |
295 | return HWC2_ERROR_NONE; |
296 | } |
297 | else { |
298 | MESON_LOGE("[%s]: no support display config: %d", __func__, config); |
299 | return HWC2_ERROR_UNSUPPORTED; |
300 | } |
301 | } |
302 | |
303 | int32_t ActiveModeMgr::updateHwcActiveConfig( |
304 | const char * activeMode) { |
305 | MESON_LOGD("ActiveModeMgr::updateHwcActiveConfig (mode)"); |
306 | for (auto it = mHwcActiveModes.begin(); it != mHwcActiveModes.end(); ++it) { |
307 | if (strncmp(activeMode, it->second.name, DRM_DISPLAY_MODE_LEN) == 0 |
308 | && !isFracRate(it->second.refreshRate)) { |
309 | mDefaultModeSupport = true; |
310 | mHwcActiveConfigId = mHwcActiveModes.size()-1; |
311 | MESON_LOGD("updateActiveConfig to (%s, %d)", activeMode, mHwcActiveConfigId); |
312 | return HWC2_ERROR_NONE; |
313 | } |
314 | } |
315 | |
316 | mHwcActiveConfigId = mHwcActiveModes.size()-1; |
317 | MESON_LOGD("updateActiveConfig something error to (%s, %d)", activeMode, mHwcActiveConfigId); |
318 | |
319 | return HWC2_ERROR_NONE; |
320 | } |
321 | |
322 | |
323 | int32_t ActiveModeMgr::updateSfActiveConfig( |
324 | uint32_t configId, drm_mode_info_t cfg) { |
325 | mActiveConfigStr = cfg.name; |
326 | mSfActiveConfigId = configId; |
327 | mFakeConfigId = mSfActiveModes.size()-1; |
328 | MESON_LOGD("updateSfActiveConfig(mode) to (%s, %d)", cfg.name, mSfActiveConfigId); |
329 | return HWC2_ERROR_NONE; |
330 | } |
331 | |
332 | int32_t ActiveModeMgr::getActiveConfig( |
333 | uint32_t * outConfig, int32_t caller __unused) { |
334 | *outConfig = mExtModeSet ? mSfActiveConfigId : mFakeConfigId; |
335 | /* MESON_LOGV("[%s]: ret %d, Sf id %d, Hwc id %d, fake id %d, mExtModeSet %d, caller (%s)", |
336 | __func__ ,*outConfig, mSfActiveConfigId, mHwcActiveConfigId, mFakeConfigId, |
337 | mExtModeSet, caller == CALL_FROM_SF ? "SF" : "HWC");*/ |
338 | return HWC2_ERROR_NONE; |
339 | } |
340 | |
341 | int32_t ActiveModeMgr::setActiveConfig( |
342 | uint32_t configId) { |
343 | std::map<uint32_t, drm_mode_info_t>::iterator it = |
344 | mSfActiveModes.find(configId); |
345 | MESON_LOGD("ActiveModeMgr::setActiveConfig %d", configId); |
346 | if (it != mSfActiveModes.end()) { |
347 | drm_mode_info_t cfg = it->second; |
348 | |
349 | // update real active config. |
350 | updateSfActiveConfig(configId, cfg); |
351 | |
352 | // It is possible that default mode is not supported by the sink |
353 | // and it was only advertised to the FWK to force 1080p UI. |
354 | // Trap this case and do nothing. FWK will keep thinking |
355 | // 1080p is supported and set. |
356 | if (!mDefaultModeSupport |
357 | && strncmp(cfg.name, mDefaultMode.name, DRM_DISPLAY_MODE_LEN) == 0) { |
358 | MESON_LOGD("setActiveConfig default mode not supported"); |
359 | return HWC2_ERROR_NONE; |
360 | } |
361 | |
362 | mExtModeSet = true; |
363 | mCallOnHotPlug = false; |
364 | mConnector->setMode(cfg); |
365 | mCrtc->setMode(cfg); |
366 | MESON_LOGD("setActiveConfig %d, mExtModeSet %d", |
367 | configId, mExtModeSet); |
368 | return HWC2_ERROR_NONE; |
369 | } else { |
370 | MESON_LOGE("set invalild active config (%d)", configId); |
371 | return HWC2_ERROR_NOT_VALIDATED; |
372 | } |
373 | } |
374 | |
375 | void ActiveModeMgr::reset() { |
376 | mHwcActiveModes.clear(); |
377 | mSfActiveModes.clear(); |
378 | mDefaultModeSupport = false; |
379 | mSfActiveConfigId = mHwcActiveConfigId = mFakeConfigId = -1; |
380 | mExtModeSet = false; |
381 | mCallOnHotPlug = true; |
382 | } |
383 | |
384 | void ActiveModeMgr::resetTags() { |
385 | if (!useFakeMode) { |
386 | mCallOnHotPlug = true; |
387 | mExtModeSet = false; |
388 | } |
389 | }; |
390 | |
391 | |
392 | const drm_mode_info_t ActiveModeMgr::findMatchedMode( |
393 | uint32_t width, uint32_t height, float refreshrate) { |
394 | uint32_t i = 0; |
395 | uint32_t size = ARRAY_SIZE(mode_info); |
396 | for (i = 0; i < size; i++) { |
397 | if (mode_info[i].pixelW == width && |
398 | mode_info[i].pixelH == height && |
399 | mode_info[i].refreshRate == refreshrate) { |
400 | return mode_info[i]; |
401 | } |
402 | } |
403 | return mode_info[size-1]; |
404 | } |
405 | |
406 | void ActiveModeMgr::dump(String8 & dumpstr) { |
407 | dumpstr.appendFormat("ActiveModeMgr: %s\n", mActiveConfigStr.c_str()); |
408 | dumpstr.append("---------------------------------------------------------" |
409 | "-------------------------------------------------\n"); |
410 | dumpstr.append("| CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT |" |
411 | " DPI_X | DPI_Y | FRAC | mode \n"); |
412 | dumpstr.append("+------------+------------------+-----------+------------+" |
413 | "-----------+-----------+-----------+-----------+\n"); |
414 | std::map<uint32_t, drm_mode_info_t>::iterator it = |
415 | mHwcActiveModes.begin(); |
416 | for (; it != mHwcActiveModes.end(); ++it) { |
417 | int mode = it->first; |
418 | drm_mode_info_t config = it->second; |
419 | dumpstr.appendFormat("%s %2d | %.3f | %5d | %5d |" |
420 | " %3d | %3d | %d | %s \n", |
421 | (mode == (int)mHwcActiveConfigId) ? "* " : " ", |
422 | mode, |
423 | config.refreshRate, |
424 | config.pixelW, |
425 | config.pixelH, |
426 | config.dpiX, |
427 | config.dpiY, |
428 | isFracRate(config.refreshRate), |
429 | config.name); |
430 | } |
431 | dumpstr.append("---------------------------------------------------------" |
432 | "-------------------------------------------------\n"); |
433 | |
434 | dumpstr.appendFormat("ActiveModeMgr: %s\n", mActiveConfigStr.c_str()); |
435 | dumpstr.append("---------------------------------------------------------" |
436 | "-------------------------------------------------\n"); |
437 | dumpstr.append("| CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT |" |
438 | " DPI_X | DPI_Y | FRAC | mode \n"); |
439 | dumpstr.append("+------------+------------------+-----------+------------+" |
440 | "-----------+-----------+-----------+-----------+\n"); |
441 | std::map<uint32_t, drm_mode_info_t>::iterator it1 = |
442 | mSfActiveModes.begin(); |
443 | for (; it1 != mSfActiveModes.end(); ++it1) { |
444 | int mode1 = it1->first; |
445 | drm_mode_info_t config = it1->second; |
446 | dumpstr.appendFormat("%s %2d | %.3f | %5d | %5d |" |
447 | " %3d | %3d | %d | %s \n", |
448 | (mode1 == (int)mSfActiveConfigId) ? "* " : " ", |
449 | mode1, |
450 | config.refreshRate, |
451 | config.pixelW, |
452 | config.pixelH, |
453 | config.dpiX, |
454 | config.dpiY, |
455 | isFracRate(config.refreshRate), |
456 | config.name); |
457 | } |
458 | dumpstr.append("---------------------------------------------------------" |
459 | "-------------------------------------------------\n"); |
460 | } |
461 | |
462 |