1 /*
2 * Copyright (C) 2019 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 "ExynosDisplayDrmInterface.h"
20
21 #include <aidl/android/hardware/drm/HdcpLevels.h>
22 #include <cutils/properties.h>
23 #include <drm.h>
24 #include <drm/drm_fourcc.h>
25 #include <sys/types.h>
26 #include <xf86drm.h>
27
28 #include <algorithm>
29 #include <numeric>
30
31 #include "BrightnessController.h"
32 #include "ExynosHWCDebug.h"
33 #include "ExynosHWCHelper.h"
34 #include "ExynosLayer.h"
35 #include "ExynosPrimaryDisplay.h"
36 #include "HistogramController.h"
37
38 using ::aidl::android::hardware::drm::HdcpLevel;
39 using ::aidl::android::hardware::drm::HdcpLevels;
40 using namespace std::chrono_literals;
41 using namespace SOC_VERSION;
42
43 constexpr uint32_t MAX_PLANE_NUM = 3;
44 constexpr uint32_t CBCR_INDEX = 1;
45 constexpr float DISPLAY_LUMINANCE_UNIT = 10000;
46 constexpr auto vsyncPeriodTag = "VsyncPeriod";
47
48 typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr;
49
50 struct _drmModeAtomicReqItem {
51 uint32_t object_id;
52 uint32_t property_id;
53 uint64_t value;
54 uint32_t cursor;
55 };
56
57 struct _drmModeAtomicReq {
58 uint32_t cursor;
59 uint32_t size_items;
60 drmModeAtomicReqItemPtr items;
61 };
62
63 using namespace vendor::graphics;
64
65 extern struct exynos_hwc_control exynosHWCControl;
66 static const int32_t kUmPerInch = 25400;
67
writeIntToKernelFile(const char * path,const int value)68 int writeIntToKernelFile(const char* path, const int value) {
69 std::ofstream ofs(path);
70
71 if (!ofs.is_open()) {
72 ALOGW("%s(): unable to open %s (%s)", __func__, path, strerror(errno));
73 return -1;
74 }
75
76 ofs << value << std::endl;
77
78 return 0;
79 }
80
~FramebufferManager()81 FramebufferManager::~FramebufferManager()
82 {
83 {
84 Mutex::Autolock lock(mMutex);
85 mRmFBThreadRunning = false;
86 }
87 mFlipDone.signal();
88 mRmFBThread.join();
89 }
90
init(int drmFd)91 void FramebufferManager::init(int drmFd)
92 {
93 mDrmFd = drmFd;
94 mRmFBThreadRunning = true;
95 mRmFBThread = std::thread(&FramebufferManager::removeFBsThreadRoutine, this);
96 pthread_setname_np(mRmFBThread.native_handle(), "RemoveFBsThread");
97 }
98
getBufHandleFromFd(int fd)99 uint32_t FramebufferManager::getBufHandleFromFd(int fd)
100 {
101 uint32_t gem_handle = 0;
102
103 int ret = drmPrimeFDToHandle(mDrmFd, fd, &gem_handle);
104 if (ret) {
105 ALOGE("drmPrimeFDToHandle failed with fd %d error %d (%s)", fd, ret, strerror(errno));
106 }
107 return gem_handle;
108 }
109
addFB2WithModifiers(uint32_t state,uint32_t width,uint32_t height,uint32_t drmFormat,const DrmArray<uint32_t> & handles,const DrmArray<uint32_t> & pitches,const DrmArray<uint32_t> & offsets,const DrmArray<uint64_t> & modifier,uint32_t * buf_id,uint32_t flags)110 int FramebufferManager::addFB2WithModifiers(uint32_t state, uint32_t width, uint32_t height,
111 uint32_t drmFormat, const DrmArray<uint32_t> &handles,
112 const DrmArray<uint32_t> &pitches,
113 const DrmArray<uint32_t> &offsets,
114 const DrmArray<uint64_t> &modifier, uint32_t *buf_id,
115 uint32_t flags) {
116 if (CC_UNLIKELY(!validateLayerInfo(state, drmFormat, handles, modifier))) {
117 return -EINVAL;
118 }
119
120 int ret = drmModeAddFB2WithModifiers(mDrmFd, width, height, drmFormat, handles.data(),
121 pitches.data(), offsets.data(), modifier.data(), buf_id,
122 flags);
123 if (ret) ALOGE("Failed to add fb error %d\n", ret);
124
125 return ret;
126 }
127
validateLayerInfo(uint32_t state,uint32_t drmFormat,const DrmArray<uint32_t> & handles,const DrmArray<uint64_t> & modifier)128 bool FramebufferManager::validateLayerInfo(uint32_t state, uint32_t drmFormat,
129 const DrmArray<uint32_t> &handles,
130 const DrmArray<uint64_t> &modifier) {
131 switch (state) {
132 case exynos_win_config_data::WIN_STATE_RCD:
133 return drmFormat == DRM_FORMAT_C8 && handles[0] != 0 && handles[1] == 0 &&
134 modifier[0] == 0;
135 }
136
137 return true;
138 }
139
checkShrink()140 void FramebufferManager::checkShrink() {
141 Mutex::Autolock lock(mMutex);
142
143 mCacheShrinkPending = mCachedLayerBuffers.size() > MAX_CACHED_LAYERS;
144 mCacheSecureShrinkPending = mCachedSecureLayerBuffers.size() > MAX_CACHED_SECURE_LAYERS;
145 }
146
cleanup(const ExynosLayer * layer)147 void FramebufferManager::cleanup(const ExynosLayer *layer) {
148 ATRACE_CALL();
149
150 Mutex::Autolock lock(mMutex);
151 auto clean = [&](std::map<const ExynosLayer *, FBList> &layerBuffs) {
152 if (auto it = layerBuffs.find(layer); it != layerBuffs.end()) {
153 mCleanBuffers.splice(mCleanBuffers.end(), std::move(it->second));
154 layerBuffs.erase(it);
155 }
156 };
157 clean(mCachedLayerBuffers);
158 clean(mCachedSecureLayerBuffers);
159 }
160
removeFBsThreadRoutine()161 void FramebufferManager::removeFBsThreadRoutine()
162 {
163 FBList cleanupBuffers;
164 while (true) {
165 {
166 Mutex::Autolock lock(mMutex);
167 if (!mRmFBThreadRunning) {
168 break;
169 }
170 mFlipDone.wait(mMutex);
171 cleanupBuffers.splice(cleanupBuffers.end(), mCleanBuffers);
172 }
173 ATRACE_NAME("cleanup framebuffers");
174 cleanupBuffers.clear();
175 }
176 }
177
getBuffer(const exynos_win_config_data & config,uint32_t & fbId)178 int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint32_t &fbId) {
179 ATRACE_CALL();
180 int ret = NO_ERROR;
181 int drmFormat = DRM_FORMAT_UNDEFINED;
182 uint32_t bpp = 0;
183 uint32_t bufferNum, planeNum = 0;
184 uint32_t bufWidth, bufHeight = 0;
185 bool isSecureBuffer = config.protection;
186 DrmArray<uint32_t> pitches = {0};
187 DrmArray<uint32_t> offsets = {0};
188 DrmArray<uint64_t> modifiers = {0};
189 DrmArray<uint32_t> handles = {0};
190
191 if (config.protection) modifiers[0] |= DRM_FORMAT_MOD_PROTECTION;
192
193 if (config.state == config.WIN_STATE_BUFFER || config.state == config.WIN_STATE_RCD) {
194 bufWidth = config.src.f_w;
195 bufHeight = config.src.f_h;
196
197 auto exynosFormat = halFormatToExynosFormat(config.format, config.compressionInfo.type);
198 if (exynosFormat == nullptr) {
199 ALOGE("%s:: unknown HAL format (%d)", __func__, config.format);
200 return -EINVAL;
201 }
202
203 drmFormat = exynosFormat->drmFormat;
204 if (drmFormat == DRM_FORMAT_UNDEFINED) {
205 ALOGE("%s:: unknown drm format (%d)", __func__, config.format);
206 return -EINVAL;
207 }
208
209 bpp = getBytePerPixelOfPrimaryPlane(config.format);
210 if ((bufferNum = exynosFormat->bufferNum) == 0) {
211 ALOGE("%s:: getBufferNumOfFormat(%d) error", __func__, config.format);
212 return -EINVAL;
213 }
214 if (((planeNum = exynosFormat->planeNum) == 0) || (planeNum > MAX_PLANE_NUM)) {
215 ALOGE("%s:: getPlaneNumOfFormat(%d) error, planeNum(%d)", __func__, config.format,
216 planeNum);
217 return -EINVAL;
218 }
219
220 fbId = findCachedFbId(config.layer, isSecureBuffer,
221 [bufferDesc = Framebuffer::BufferDesc{config.buffer_id, drmFormat,
222 config.protection}](
223 auto& buffer) { return buffer->bufferDesc == bufferDesc; });
224 if (fbId != 0) {
225 return NO_ERROR;
226 }
227
228 if (config.compressionInfo.type == COMP_TYPE_AFBC) {
229 uint64_t compressed_modifier = config.compressionInfo.modifier;
230 switch (config.comp_src) {
231 case DPP_COMP_SRC_G2D:
232 compressed_modifier |= AFBC_FORMAT_MOD_SOURCE_G2D;
233 break;
234 case DPP_COMP_SRC_GPU:
235 compressed_modifier |= AFBC_FORMAT_MOD_SOURCE_GPU;
236 break;
237 default:
238 break;
239 }
240 modifiers[0] |= DRM_FORMAT_MOD_ARM_AFBC(compressed_modifier);
241 } else if (config.compressionInfo.type == COMP_TYPE_SBWC) {
242 modifiers[0] |= DRM_FORMAT_MOD_SAMSUNG_SBWC(config.compressionInfo.modifier);
243 }
244
245 for (uint32_t bufferIndex = 0; bufferIndex < bufferNum; bufferIndex++) {
246 pitches[bufferIndex] = config.src.f_w * bpp;
247 modifiers[bufferIndex] = modifiers[0];
248 handles[bufferIndex] = getBufHandleFromFd(config.fd_idma[bufferIndex]);
249 if (handles[bufferIndex] == 0) {
250 return -ENOMEM;
251 }
252 }
253
254 if ((bufferNum == 1) && (planeNum > bufferNum)) {
255 /* offset for cbcr */
256 offsets[CBCR_INDEX] =
257 getExynosBufferYLength(config.src.f_w, config.src.f_h, config.format);
258 for (uint32_t planeIndex = 1; planeIndex < planeNum; planeIndex++) {
259 handles[planeIndex] = handles[0];
260 pitches[planeIndex] = pitches[0];
261 modifiers[planeIndex] = modifiers[0];
262 }
263 }
264 } else if (config.state == config.WIN_STATE_COLOR) {
265 bufWidth = config.dst.w;
266 bufHeight = config.dst.h;
267 modifiers[0] |= DRM_FORMAT_MOD_SAMSUNG_COLORMAP;
268 drmFormat = DRM_FORMAT_BGRA8888;
269 bufferNum = 0;
270 handles[0] = 0xff000000;
271 bpp = getBytePerPixelOfPrimaryPlane(HAL_PIXEL_FORMAT_BGRA_8888);
272 pitches[0] = config.dst.w * bpp;
273 fbId = findCachedFbId(config.layer, isSecureBuffer,
274 [colorDesc = Framebuffer::SolidColorDesc{bufWidth, bufHeight}](
275 auto& buffer) { return buffer->colorDesc == colorDesc; });
276 if (fbId != 0) {
277 return NO_ERROR;
278 }
279 } else {
280 ALOGE("%s:: unknown config state(%d)", __func__, config.state);
281 return -EINVAL;
282 }
283
284 ret = addFB2WithModifiers(config.state, bufWidth, bufHeight, drmFormat, handles, pitches,
285 offsets, modifiers, &fbId, modifiers[0] ? DRM_MODE_FB_MODIFIERS : 0);
286
287 for (uint32_t bufferIndex = 0; bufferIndex < bufferNum; bufferIndex++) {
288 freeBufHandle(handles[bufferIndex]);
289 }
290
291 if (ret) {
292 ALOGE("%s:: Failed to add FB, fb_id(%d), ret(%d), f_w: %d, f_h: %d, dst.w: %d, dst.h: %d, "
293 "format: %d %4.4s, buf_handles[%d, %d, %d, %d], "
294 "pitches[%d, %d, %d, %d], offsets[%d, %d, %d, %d], modifiers[%#" PRIx64 ", %#" PRIx64
295 ", %#" PRIx64 ", %#" PRIx64 "]",
296 __func__, fbId, ret, config.src.f_w, config.src.f_h, config.dst.w, config.dst.h,
297 drmFormat, (char *)&drmFormat, handles[0], handles[1], handles[2], handles[3],
298 pitches[0], pitches[1], pitches[2], pitches[3], offsets[0], offsets[1], offsets[2],
299 offsets[3], modifiers[0], modifiers[1], modifiers[2], modifiers[3]);
300 return ret;
301 }
302
303 if (config.layer || config.buffer_id) {
304 Mutex::Autolock lock(mMutex);
305 auto& cachedBuffers = (!isSecureBuffer) ? mCachedLayerBuffers[config.layer]
306 : mCachedSecureLayerBuffers[config.layer];
307 auto maxCachedBufferSize = (!isSecureBuffer) ? MAX_CACHED_BUFFERS_PER_LAYER
308 : MAX_CACHED_SECURE_BUFFERS_PER_LAYER;
309 markInuseLayerLocked(config.layer, isSecureBuffer);
310
311 if (cachedBuffers.size() > maxCachedBufferSize) {
312 ALOGW("FBManager: cached buffers size %zu exceeds limitation(%zu) while adding fbId %d",
313 cachedBuffers.size(), maxCachedBufferSize, fbId);
314 mCleanBuffers.splice(mCleanBuffers.end(), cachedBuffers);
315 }
316
317 if (config.state == config.WIN_STATE_COLOR) {
318 cachedBuffers.emplace_front(
319 new Framebuffer(mDrmFd, fbId,
320 Framebuffer::SolidColorDesc{bufWidth, bufHeight}));
321 } else {
322 cachedBuffers.emplace_front(
323 new Framebuffer(mDrmFd, fbId,
324 Framebuffer::BufferDesc{config.buffer_id, drmFormat,
325 config.protection}));
326 }
327 } else {
328 ALOGW("FBManager: possible leakage fbId %d was created", fbId);
329 }
330
331 return 0;
332 }
333
flip(const bool hasSecureBuffer)334 void FramebufferManager::flip(const bool hasSecureBuffer) {
335 bool needCleanup = false;
336 {
337 Mutex::Autolock lock(mMutex);
338 destroyUnusedLayersLocked();
339 if (!hasSecureBuffer) {
340 destroyAllSecureBuffersLocked();
341 }
342
343 needCleanup = mCleanBuffers.size() > 0;
344 }
345
346 if (needCleanup) {
347 mFlipDone.signal();
348 }
349 }
350
releaseAll()351 void FramebufferManager::releaseAll()
352 {
353 Mutex::Autolock lock(mMutex);
354 mCachedLayerBuffers.clear();
355 mCachedSecureLayerBuffers.clear();
356 mCleanBuffers.clear();
357 }
358
freeBufHandle(uint32_t handle)359 void FramebufferManager::freeBufHandle(uint32_t handle) {
360 if (handle == 0) {
361 return;
362 }
363
364 struct drm_gem_close gem_close {
365 .handle = handle
366 };
367 int ret = drmIoctl(mDrmFd, DRM_IOCTL_GEM_CLOSE, &gem_close);
368 if (ret) {
369 ALOGE("Failed to close gem handle 0x%x with error %d\n", handle, ret);
370 }
371 }
372
markInuseLayerLocked(const ExynosLayer * layer,const bool isSecureBuffer)373 void FramebufferManager::markInuseLayerLocked(const ExynosLayer* layer, const bool isSecureBuffer) {
374 if (!isSecureBuffer && mCacheShrinkPending) {
375 mCachedLayersInuse.insert(layer);
376 }
377
378 if (isSecureBuffer && mCacheSecureShrinkPending) {
379 mCachedSecureLayersInuse.insert(layer);
380 }
381 }
382
destroyUnusedLayersLocked()383 void FramebufferManager::destroyUnusedLayersLocked() {
384 auto destroyUnusedLayers =
385 [&](const bool &cacheShrinkPending, std::set<const ExynosLayer *> &cachedLayersInuse,
386 std::map<const ExynosLayer *, FBList> &cachedLayerBuffers) -> bool {
387 if (!cacheShrinkPending || cachedLayersInuse.size() == cachedLayerBuffers.size()) {
388 cachedLayersInuse.clear();
389 return false;
390 }
391
392 for (auto layer = cachedLayerBuffers.begin(); layer != cachedLayerBuffers.end();) {
393 if (cachedLayersInuse.find(layer->first) == cachedLayersInuse.end()) {
394 mCleanBuffers.splice(mCleanBuffers.end(), std::move(layer->second));
395 layer = cachedLayerBuffers.erase(layer);
396 } else {
397 ++layer;
398 }
399 }
400 cachedLayersInuse.clear();
401 return true;
402 };
403
404 auto cachedLayerSize = mCachedLayerBuffers.size();
405 if (destroyUnusedLayers(mCacheShrinkPending, mCachedLayersInuse, mCachedLayerBuffers)) {
406 ALOGW("FBManager: shrink cached layers from %zu to %zu", cachedLayerSize,
407 mCachedLayerBuffers.size());
408 }
409
410 cachedLayerSize = mCachedSecureLayerBuffers.size();
411 if (destroyUnusedLayers(mCacheSecureShrinkPending, mCachedSecureLayersInuse,
412 mCachedSecureLayerBuffers)) {
413 ALOGW("FBManager: shrink cached secure layers from %zu to %zu", cachedLayerSize,
414 mCachedSecureLayerBuffers.size());
415 }
416 }
417
destroyAllSecureBuffersLocked()418 void FramebufferManager::destroyAllSecureBuffersLocked() {
419 for (auto& [layer, bufferList] : mCachedSecureLayerBuffers) {
420 if (bufferList.size()) {
421 mCleanBuffers.splice(mCleanBuffers.end(), bufferList, bufferList.begin(),
422 bufferList.end());
423 }
424 }
425 mCachedSecureLayerBuffers.clear();
426 }
427
destroyAllSecureBuffers()428 void FramebufferManager::destroyAllSecureBuffers() {
429 bool needCleanup = false;
430 {
431 Mutex::Autolock lock(mMutex);
432 destroyAllSecureBuffersLocked();
433 needCleanup = mCleanBuffers.size() > 0;
434 }
435 if (needCleanup) {
436 mFlipDone.signal();
437 }
438 }
439
uncacheLayerBuffers(const ExynosLayer * layer,const std::vector<buffer_handle_t> & buffers)440 int32_t FramebufferManager::uncacheLayerBuffers(const ExynosLayer* layer,
441 const std::vector<buffer_handle_t>& buffers) {
442 std::set<Framebuffer::BufferDesc> removedBufferDescs;
443 for (auto buffer : buffers) {
444 VendorGraphicBufferMeta gmeta(buffer);
445 removedBufferDescs.insert(
446 Framebuffer::BufferDesc{.bufferId = gmeta.unique_id,
447 .drmFormat =
448 halFormatToDrmFormat(gmeta.format,
449 getCompressionType(buffer)),
450 .isSecure =
451 (getDrmMode(gmeta.producer_usage) == SECURE_DRM)});
452 }
453 bool needCleanup = false;
454 {
455 Mutex::Autolock lock(mMutex);
456 auto destroyCachedBuffersLocked =
457 [&](std::map<const ExynosLayer*, FBList>& cachedLayerBuffers) REQUIRES(mMutex) {
458 if (auto layerIter = cachedLayerBuffers.find(layer);
459 layerIter != cachedLayerBuffers.end()) {
460 auto& fbList = layerIter->second;
461 for (auto it = fbList.begin(); it != fbList.end();) {
462 auto bufferIter = it++;
463 if (removedBufferDescs.count((*bufferIter)->bufferDesc)) {
464 mCleanBuffers.splice(mCleanBuffers.end(), fbList, bufferIter);
465 needCleanup = true;
466 }
467 }
468 }
469 };
470 destroyCachedBuffersLocked(mCachedLayerBuffers);
471 destroyCachedBuffersLocked(mCachedSecureLayerBuffers);
472 }
473 if (needCleanup) {
474 mFlipDone.signal();
475 }
476 return NO_ERROR;
477 }
478
uncacheLayerBuffers(const ExynosLayer * layer,const std::vector<buffer_handle_t> & buffers)479 int32_t ExynosDisplayDrmInterface::uncacheLayerBuffers(
480 const ExynosLayer* layer, const std::vector<buffer_handle_t>& buffers) {
481 return mFBManager.uncacheLayerBuffers(layer, buffers);
482 }
483
destroyLayer(ExynosLayer * layer)484 void ExynosDisplayDrmInterface::destroyLayer(ExynosLayer *layer) {
485 mFBManager.cleanup(layer);
486 }
487
getDisplayIdleTimerSupport(bool & outSupport)488 int32_t ExynosDisplayDrmInterface::getDisplayIdleTimerSupport(bool &outSupport) {
489 if (isVrrSupported()) {
490 outSupport = false;
491 return NO_ERROR;
492 } else if (isMrrV2()) {
493 // Retuen true to avoid SF idle timer working. We insert frames manually
494 // for pseudo VRR, so ideally panel idle should be disabled in the driver.
495 outSupport = true;
496 return NO_ERROR;
497 }
498
499 auto [ret, support] = mDrmConnector->panel_idle_support().value();
500 if (ret) {
501 ALOGI("no panel_idle_support drm property or invalid value (%d)", ret);
502 outSupport = false;
503 } else {
504 outSupport = (support > 0);
505 }
506
507 return NO_ERROR;
508 }
509
getDefaultModeId(int32_t * modeId)510 int32_t ExynosDisplayDrmInterface::getDefaultModeId(int32_t *modeId) {
511 if (modeId == nullptr) return HWC2_ERROR_BAD_PARAMETER;
512
513 *modeId = mDrmConnector->get_preferred_mode_id();
514 return NO_ERROR;
515 }
516
ExynosDisplayDrmInterface(ExynosDisplay * exynosDisplay)517 ExynosDisplayDrmInterface::ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay):
518 mMonitorDescription{0}
519 {
520 mType = INTERFACE_TYPE_DRM;
521 init(exynosDisplay);
522 }
523
~ExynosDisplayDrmInterface()524 ExynosDisplayDrmInterface::~ExynosDisplayDrmInterface()
525 {
526 if (mActiveModeState.blob_id)
527 mDrmDevice->DestroyPropertyBlob(mActiveModeState.blob_id);
528 if (mActiveModeState.old_blob_id)
529 mDrmDevice->DestroyPropertyBlob(mActiveModeState.old_blob_id);
530 if (mDesiredModeState.blob_id)
531 mDrmDevice->DestroyPropertyBlob(mDesiredModeState.blob_id);
532 if (mDesiredModeState.old_blob_id)
533 mDrmDevice->DestroyPropertyBlob(mDesiredModeState.old_blob_id);
534 if (mPartialRegionState.blob_id)
535 mDrmDevice->DestroyPropertyBlob(mPartialRegionState.blob_id);
536 }
537
init(ExynosDisplay * exynosDisplay)538 void ExynosDisplayDrmInterface::init(ExynosDisplay *exynosDisplay)
539 {
540 mExynosDisplay = exynosDisplay;
541 mDisplayTraceName = mExynosDisplay->mDisplayTraceName;
542 mDrmDevice = NULL;
543 mDrmCrtc = NULL;
544 mDrmConnector = NULL;
545 }
546
parseBlendEnums(const DrmProperty & property)547 void ExynosDisplayDrmInterface::parseBlendEnums(const DrmProperty &property)
548 {
549 const std::vector<std::pair<uint32_t, const char *>> blendEnums = {
550 {HWC2_BLEND_MODE_NONE, "None"},
551 {HWC2_BLEND_MODE_PREMULTIPLIED, "Pre-multiplied"},
552 {HWC2_BLEND_MODE_COVERAGE, "Coverage"},
553 };
554
555 ALOGD("Init blend enums");
556 DrmEnumParser::parseEnums(property, blendEnums, mBlendEnums);
557 for (auto &e : mBlendEnums) {
558 ALOGD("blend [hal: %d, drm: %" PRId64 "]", e.first, e.second);
559 }
560 }
561
parseStandardEnums(const DrmProperty & property)562 void ExynosDisplayDrmInterface::parseStandardEnums(const DrmProperty &property)
563 {
564 const std::vector<std::pair<uint32_t, const char *>> standardEnums = {
565 {HAL_DATASPACE_STANDARD_UNSPECIFIED, "Unspecified"},
566 {HAL_DATASPACE_STANDARD_BT709, "BT709"},
567 {HAL_DATASPACE_STANDARD_BT601_625, "BT601_625"},
568 {HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED, "BT601_625_UNADJUSTED"},
569 {HAL_DATASPACE_STANDARD_BT601_525, "BT601_525"},
570 {HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED, "BT601_525_UNADJUSTED"},
571 {HAL_DATASPACE_STANDARD_BT2020, "BT2020"},
572 {HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE, "BT2020_CONSTANT_LUMINANCE"},
573 {HAL_DATASPACE_STANDARD_BT470M, "BT470M"},
574 {HAL_DATASPACE_STANDARD_FILM, "FILM"},
575 {HAL_DATASPACE_STANDARD_DCI_P3, "DCI-P3"},
576 {HAL_DATASPACE_STANDARD_ADOBE_RGB, "Adobe RGB"},
577 };
578
579 ALOGD("Init standard enums");
580 DrmEnumParser::parseEnums(property, standardEnums, mStandardEnums);
581 for (auto &e : mStandardEnums) {
582 ALOGD("standard [hal: %d, drm: %" PRId64 "]",
583 e.first >> HAL_DATASPACE_STANDARD_SHIFT, e.second);
584 }
585 }
586
parseTransferEnums(const DrmProperty & property)587 void ExynosDisplayDrmInterface::parseTransferEnums(const DrmProperty &property)
588 {
589 const std::vector<std::pair<uint32_t, const char *>> transferEnums = {
590 {HAL_DATASPACE_TRANSFER_UNSPECIFIED, "Unspecified"},
591 {HAL_DATASPACE_TRANSFER_LINEAR, "Linear"},
592 {HAL_DATASPACE_TRANSFER_SRGB, "sRGB"},
593 {HAL_DATASPACE_TRANSFER_SMPTE_170M, "SMPTE 170M"},
594 {HAL_DATASPACE_TRANSFER_GAMMA2_2, "Gamma 2.2"},
595 {HAL_DATASPACE_TRANSFER_GAMMA2_6, "Gamma 2.6"},
596 {HAL_DATASPACE_TRANSFER_GAMMA2_8, "Gamma 2.8"},
597 {HAL_DATASPACE_TRANSFER_ST2084, "ST2084"},
598 {HAL_DATASPACE_TRANSFER_HLG, "HLG"},
599 };
600
601 ALOGD("Init transfer enums");
602 DrmEnumParser::parseEnums(property, transferEnums, mTransferEnums);
603 for (auto &e : mTransferEnums) {
604 ALOGD("transfer [hal: %d, drm: %" PRId64 "]",
605 e.first >> HAL_DATASPACE_TRANSFER_SHIFT, e.second);
606 }
607 }
608
parseRangeEnums(const DrmProperty & property)609 void ExynosDisplayDrmInterface::parseRangeEnums(const DrmProperty &property)
610 {
611 const std::vector<std::pair<uint32_t, const char *>> rangeEnums = {
612 {HAL_DATASPACE_RANGE_UNSPECIFIED, "Unspecified"},
613 {HAL_DATASPACE_RANGE_FULL, "Full"},
614 {HAL_DATASPACE_RANGE_LIMITED, "Limited"},
615 {HAL_DATASPACE_RANGE_EXTENDED, "Extended"},
616 };
617
618 ALOGD("Init range enums");
619 DrmEnumParser::parseEnums(property, rangeEnums, mRangeEnums);
620 for (auto &e : mRangeEnums) {
621 ALOGD("range [hal: %d, drm: %" PRId64 "]",
622 e.first >> HAL_DATASPACE_RANGE_SHIFT, e.second);
623 }
624 }
625
parseColorModeEnums(const DrmProperty & property)626 void ExynosDisplayDrmInterface::parseColorModeEnums(const DrmProperty &property)
627 {
628 const std::vector<std::pair<uint32_t, const char *>> colorModeEnums = {
629 {HAL_COLOR_MODE_NATIVE, "Native"},
630 {HAL_COLOR_MODE_DCI_P3, "DCI-P3"},
631 {HAL_COLOR_MODE_SRGB, "sRGB"},
632 };
633
634 ALOGD("Init color mode enums");
635 DrmEnumParser::parseEnums(property, colorModeEnums, mColorModeEnums);
636 for (auto &e : mColorModeEnums) {
637 ALOGD("Colormode [hal: %d, drm: %" PRId64 "]", e.first, e.second);
638 }
639 }
640
parseMipiSyncEnums(const DrmProperty & property)641 void ExynosDisplayDrmInterface::parseMipiSyncEnums(const DrmProperty &property) {
642 const std::vector<std::pair<uint32_t, const char *>> modeEnums = {
643 {toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_REFRESH_RATE), "sync_refresh_rate"},
644 {toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_LHBM), "sync_lhbm"},
645 {toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_GHBM), "sync_ghbm"},
646 {toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_BL), "sync_bl"},
647 {toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_OP_RATE), "sync_op_rate"},
648 };
649 DrmEnumParser::parseEnums(property, modeEnums, mMipiSyncEnums);
650 for (auto &e : mMipiSyncEnums) {
651 ALOGD("mipi sync [hal 0x%x, drm: %" PRId64 ", %s]", e.first, e.second,
652 modeEnums[e.first].second);
653 }
654 }
655
updateMountOrientation()656 void ExynosDisplayDrmInterface::updateMountOrientation()
657 {
658 const std::vector<std::pair<HwcMountOrientation, const char*>> orientationEnums = {
659 { HwcMountOrientation::ROT_0, "Normal" },
660 { HwcMountOrientation::ROT_90, "Left Side Up" },
661 { HwcMountOrientation::ROT_180, "Upside Down" },
662 { HwcMountOrientation::ROT_270, "Right Side Up" },
663 };
664
665 mExynosDisplay->mMountOrientation = HwcMountOrientation::ROT_0;
666 const DrmProperty &orientation = mDrmConnector->orientation();
667 if (orientation.id() == 0)
668 return;
669
670 auto [err, drmOrientation] = orientation.value();
671 if (err) {
672 ALOGW("%s failed to get drm prop value, err: %d", __func__, err);
673 return;
674 }
675
676 for (auto &e : orientationEnums) {
677 uint64_t enumValue;
678 std::tie(enumValue, err) = orientation.getEnumValueWithName(e.second);
679 if (!err && enumValue == drmOrientation) {
680 mExynosDisplay->mMountOrientation = e.first;
681 return;
682 }
683 }
684
685 ALOGW("%s ignore unrecoganized orientation %" PRId64, __func__, drmOrientation);
686 }
687
parseRCDId(const DrmProperty & property)688 void ExynosDisplayDrmInterface::parseRCDId(const DrmProperty &property) {
689 if (mExynosDisplay->mType != HWC_DISPLAY_PRIMARY) {
690 ALOGW("%s invalid display type: %d", __func__, mExynosDisplay->mType);
691 return;
692 }
693
694 if (property.id() == 0) {
695 static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId = -1;
696 return;
697 }
698
699 auto [err, rcd_id] = property.value();
700 if (err < 0) {
701 ALOGW("%s failed to get drm prop value", __func__);
702 return;
703 }
704
705 if (getSpecialChannelId(rcd_id) >= 0)
706 static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId = rcd_id;
707 }
708
getDrmDisplayId(uint32_t type,uint32_t index)709 int ExynosDisplayDrmInterface::getDrmDisplayId(uint32_t type, uint32_t index)
710 {
711 for (auto &conn: mDrmDevice->connectors()) {
712 if ((((type == HWC_DISPLAY_PRIMARY) && conn->internal()) && (index == conn->display())) ||
713 ((type == HWC_DISPLAY_EXTERNAL) && conn->external()))
714 return conn->display();
715 }
716
717 return -1;
718 }
719
initDrmDevice(DrmDevice * drmDevice)720 int32_t ExynosDisplayDrmInterface::initDrmDevice(DrmDevice *drmDevice)
721 {
722 if (mExynosDisplay == NULL) {
723 ALOGE("mExynosDisplay is not set");
724 return -EINVAL;
725 }
726 if ((mDrmDevice = drmDevice) == NULL) {
727 ALOGE("drmDevice is NULL");
728 return -EINVAL;
729 }
730
731 mFBManager.init(mDrmDevice->fd());
732
733 int drmDisplayId = getDrmDisplayId(mExynosDisplay->mType, mExynosDisplay->mIndex);
734 if (drmDisplayId < 0) {
735 ALOGE("getDrmDisplayId is failed");
736 return -EINVAL;
737 }
738
739 if (mExynosDisplay->mType != HWC_DISPLAY_EXTERNAL)
740 mReadbackInfo.init(mDrmDevice, drmDisplayId);
741
742 if ((mDrmCrtc = mDrmDevice->GetCrtcForDisplay(drmDisplayId)) == NULL) {
743 ALOGE("%s:: GetCrtcForDisplay is NULL (id: %d)",
744 mExynosDisplay->mDisplayName.c_str(), drmDisplayId);
745 return -EINVAL;
746 }
747
748 if ((mDrmConnector = mDrmDevice->GetConnectorForDisplay(drmDisplayId)) == NULL) {
749 ALOGE("%s:: GetConnectorForDisplay is NULL (id: %d)",
750 mExynosDisplay->mDisplayName.c_str(), drmDisplayId);
751 return -EINVAL;
752 }
753
754 /* Check CRTC and Connector are matched with Display Type */
755 if (((mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) && mDrmConnector->external()) ||
756 ((mExynosDisplay->mType == HWC_DISPLAY_EXTERNAL) && mDrmConnector->internal())) {
757 ALOGE("%s:: Display(id: %u) is not matched with Connector(id: %u)",
758 mExynosDisplay->mDisplayName.c_str(), drmDisplayId, mDrmConnector->id());
759 return -EINVAL;
760 }
761
762 ALOGD("%s:: display type: %d, index: %d, drmDisplayId: %d, "
763 "crtc id: %d, connector id: %d",
764 __func__, mExynosDisplay->mType, mExynosDisplay->mIndex,
765 drmDisplayId, mDrmCrtc->id(), mDrmConnector->id());
766
767 /* Mapping ExynosMPP resource with DPP Planes */
768 uint32_t numWindow = 0;
769 for (uint32_t i = 0; i < mDrmDevice->planes().size(); i++) {
770 auto &plane = mDrmDevice->planes().at(i);
771 uint32_t plane_id = plane->id();
772
773 if (!plane->zpos_property().isImmutable()) {
774 /* Plane can be used for composition */
775 ExynosMPP *exynosMPP =
776 mExynosDisplay->mResourceManager->getOtfMPPWithChannel(i);
777 if (exynosMPP == NULL)
778 HWC_LOGE(mExynosDisplay, "getOtfMPPWithChannel fail, ch(%d)", plane_id);
779 mExynosMPPsForPlane[plane_id] = exynosMPP;
780 numWindow++;
781 } else {
782 /*
783 * Plane is special purpose plane which cannot be used for compositon.
784 * It's zpos property is immutable.
785 */
786 mExynosMPPsForPlane[plane_id] = NULL;
787 }
788 }
789 setMaxWindowNum(numWindow);
790
791 if (mExynosDisplay->mMaxWindowNum != getMaxWindowNum()) {
792 ALOGE("%s:: Invalid max window number (mMaxWindowNum: %d, getMaxWindowNum(): %d",
793 __func__, mExynosDisplay->mMaxWindowNum, getMaxWindowNum());
794 return -EINVAL;
795 }
796
797 getLowPowerDrmModeModeInfo();
798
799 mDrmVSyncWorker.Init(mDrmDevice, drmDisplayId, mDisplayTraceName);
800 mDrmVSyncWorker.RegisterCallback(std::shared_ptr<VsyncCallback>(this));
801
802 if (!mDrmDevice->planes().empty()) {
803 auto &plane = mDrmDevice->planes().front();
804 parseBlendEnums(plane->blend_property());
805 parseStandardEnums(plane->standard_property());
806 parseTransferEnums(plane->transfer_property());
807 parseRangeEnums(plane->range_property());
808 }
809
810 choosePreferredConfig();
811
812 // After choosePreferredConfig, the mDrmConnector->modes array is initialized, get the panel
813 // full resolution information here.
814 if (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) {
815 retrievePanelFullResolution();
816 }
817
818 parseColorModeEnums(mDrmCrtc->color_mode_property());
819 parseMipiSyncEnums(mDrmConnector->mipi_sync());
820 updateMountOrientation();
821
822 if (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) parseRCDId(mDrmCrtc->rcd_plane_id_property());
823
824 if (mExynosDisplay->mBrightnessController &&
825 mExynosDisplay->mBrightnessController->initDrm(*mDrmDevice, *mDrmConnector)) {
826 ALOGW("%s failed to init brightness controller", __func__);
827 }
828
829 if (mExynosDisplay->mHistogramController) {
830 mExynosDisplay->mHistogramController->initDrm(*mDrmDevice, *mDrmCrtc);
831 }
832
833 mVsyncCallback.setTransientDuration(getConfigChangeDuration());
834 return NO_ERROR;
835 }
836
837
Callback(int display,int64_t timestamp)838 void ExynosDisplayDrmInterface::Callback(
839 int display, int64_t timestamp)
840 {
841 {
842 Mutex::Autolock lock(mExynosDisplay->getDisplayMutex());
843 bool configApplied = mVsyncCallback.Callback(display, timestamp);
844
845 if (configApplied) {
846 if (mVsyncCallback.getDesiredVsyncPeriod()) {
847 mExynosDisplay->resetConfigRequestStateLocked(mActiveModeState.mode.id());
848 mDrmConnector->set_active_mode(mActiveModeState.mode);
849 mVsyncCallback.resetDesiredVsyncPeriod();
850 }
851
852 /*
853 * Disable vsync if vsync config change is done
854 */
855 if (!mVsyncCallback.getVSyncEnabled()) {
856 mDrmVSyncWorker.VSyncControl(false);
857 mVsyncCallback.resetVsyncTimeStamp();
858 }
859 } else {
860 mExynosDisplay->updateConfigRequestAppliedTime();
861 }
862
863 if (!mExynosDisplay->mPlugState || !mVsyncCallback.getVSyncEnabled()) {
864 return;
865 }
866
867 // Refresh rate during enabling LHBM might be different from the one SF expects.
868 // HWC just reports the SF expected Vsync to make UI smoothness consistent even if
869 // HWC runs at different refresh rate temporarily.
870 if (!mExynosDisplay->isConfigSettingEnabled()) {
871 int64_t pendingPeriodNs =
872 mExynosDisplay->getVsyncPeriod(mExynosDisplay->mPendingConfig);
873 int64_t activePeriodNs = mExynosDisplay->getVsyncPeriod(mExynosDisplay->mActiveConfig);
874 if (pendingPeriodNs && mExynosDisplay->mLastVsyncTimestamp) {
875 if (activePeriodNs > pendingPeriodNs) {
876 DISPLAY_DRM_LOGW("wrong vsync period: %" PRId64 "us (active), %" PRId64
877 "us (pending)",
878 activePeriodNs / 1000, pendingPeriodNs / 1000);
879 } else if (activePeriodNs != pendingPeriodNs) {
880 int64_t deltaNs = timestamp - mExynosDisplay->mLastVsyncTimestamp;
881 if (deltaNs < (pendingPeriodNs - ms2ns(2))) {
882 DISPLAY_DRM_LOGI("skip mismatching Vsync callback, delta=%" PRId64 "us",
883 deltaNs / 1000);
884 return;
885 }
886 }
887 }
888 }
889 mExynosDisplay->mLastVsyncTimestamp = timestamp;
890 }
891
892 mExynosDisplay->onVsync(timestamp);
893
894 ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
895
896 if (exynosDevice->onVsync_2_4(mExynosDisplay->mDisplayId, timestamp,
897 mExynosDisplay->mVsyncPeriod)) {
898 DISPLAY_ATRACE_INT(vsyncPeriodTag, static_cast<int32_t>(mExynosDisplay->mVsyncPeriod));
899 return;
900 }
901
902 exynosDevice->onVsync(mExynosDisplay->mDisplayId, timestamp);
903 }
904
Callback(int display,int64_t timestamp)905 bool ExynosDisplayDrmInterface::ExynosVsyncCallback::Callback(
906 int display, int64_t timestamp)
907 {
908 /*
909 * keep vsync period if mVsyncTimeStamp
910 * is not initialized since vsync is enabled
911 */
912 if (mVsyncTimeStamp > 0) {
913 mVsyncPeriod = timestamp - mVsyncTimeStamp;
914 }
915
916 mVsyncTimeStamp = timestamp;
917
918 /* There was no config chage request */
919 if (!mDesiredVsyncPeriod) {
920 ATRACE_NAME("No pending desired VSync period");
921 return true;
922 }
923 /*
924 * mDesiredVsyncPeriod is nanoseconds
925 * Compare with 20% margin
926 */
927 const int error = mDesiredVsyncPeriod / 5;
928 if (abs(static_cast<int32_t>(mDesiredVsyncPeriod - mVsyncPeriod)) < error) {
929 ATRACE_NAME("Received the desired VSync period");
930 return true;
931 }
932 bool isModeSwitchTimeReached = false;
933 nsecs_t signalTime = 0;
934 {
935 std::lock_guard<std::mutex> lock(mFenceMutex);
936 signalTime = getSignalTime(mModeSetFence);
937 if (signalTime != SIGNAL_TIME_INVALID && signalTime != SIGNAL_TIME_PENDING &&
938 timestamp > (signalTime + mVsyncPeriod * mTransientDuration - error)) {
939 close(mModeSetFence);
940 mModeSetFence = -1;
941 isModeSwitchTimeReached = true;
942 }
943 }
944 if (isModeSwitchTimeReached && ATRACE_ENABLED()) {
945 std::stringstream str;
946 str << "Over the RR duration: timestamp:" << timestamp << ",signalTime:" << signalTime
947 << ",VSyncPeriod:" << mVsyncPeriod << ",desiredVsyncPeriod:" << mDesiredVsyncPeriod
948 << ",transientDuration:" << mTransientDuration;
949 ATRACE_NAME(str.str().c_str());
950 }
951
952 return isModeSwitchTimeReached;
953 }
954
getLowPowerDrmModeModeInfo()955 int32_t ExynosDisplayDrmInterface::getLowPowerDrmModeModeInfo() {
956 auto mode = mDrmConnector->lp_mode();
957
958 if (!mode.clock()) {
959 return HWC2_ERROR_UNSUPPORTED;
960 }
961
962 mDozeDrmMode = mode;
963
964 return NO_ERROR;
965 }
966
setLowPowerMode()967 int32_t ExynosDisplayDrmInterface::setLowPowerMode() {
968 if (!isDozeModeAvailable()) {
969 return HWC2_ERROR_UNSUPPORTED;
970 }
971
972 uint32_t mm_width = mDrmConnector->mm_width();
973 uint32_t mm_height = mDrmConnector->mm_height();
974
975 mExynosDisplay->mXres = mDozeDrmMode.h_display();
976 mExynosDisplay->mYres = mDozeDrmMode.v_display();
977 // in nanoseconds
978 mExynosDisplay->mVsyncPeriod = static_cast<uint32_t>(mDozeDrmMode.te_period());
979 // Dots per 1000 inches
980 mExynosDisplay->mXdpi = mm_width ? (mDozeDrmMode.h_display() * kUmPerInch) / mm_width : -1;
981 // Dots per 1000 inches
982 mExynosDisplay->mYdpi = mm_height ? (mDozeDrmMode.v_display() * kUmPerInch) / mm_height : -1;
983
984 mExynosDisplay->mRefreshRate = static_cast<int32_t>(mDozeDrmMode.v_refresh());
985
986 return setActiveDrmMode(mDozeDrmMode);
987 }
988
setPowerMode(int32_t mode)989 int32_t ExynosDisplayDrmInterface::setPowerMode(int32_t mode)
990 {
991 int ret = 0;
992 uint64_t dpms_value = 0;
993 if (mode == HWC_POWER_MODE_OFF) {
994 dpms_value = DRM_MODE_DPMS_OFF;
995 } else {
996 dpms_value = DRM_MODE_DPMS_ON;
997 }
998
999 const DrmProperty &prop = mDrmConnector->dpms_property();
1000 if ((ret = drmModeConnectorSetProperty(mDrmDevice->fd(), mDrmConnector->id(), prop.id(),
1001 dpms_value)) != NO_ERROR) {
1002 HWC_LOGE(mExynosDisplay, "setPower mode ret (%d)", ret);
1003 }
1004
1005 if (mExynosDisplay->mDevice->mNumPrimaryDisplays >= 2 &&
1006 mExynosDisplay->mType == HWC_DISPLAY_PRIMARY && mode == HWC_POWER_MODE_OFF) {
1007 ExynosDisplay* external_display =
1008 mExynosDisplay->mDevice->getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0));
1009 ExynosDisplayDrmInterface* external_display_intf = external_display
1010 ? static_cast<ExynosDisplayDrmInterface*>(external_display->mDisplayInterface.get())
1011 : nullptr;
1012 if (external_display && external_display->mPowerModeState != HWC_POWER_MODE_OFF) {
1013 ALOGI("setPowerMode: display %s power state changed, while external display is active",
1014 mExynosDisplay->mDisplayTraceName.c_str());
1015 // Primary display has powered down, while external display doesn't have a borrowed
1016 // decon, we can now reassign the powered off decon to the external displ.
1017 // (Plug in during DCD mode case)
1018 if (external_display_intf && external_display_intf->borrowedCrtcFrom() == nullptr) {
1019 ALOGI("setPowerMode: DCD case - display %s powered off, reuse decon for external",
1020 mExynosDisplay->mDisplayTraceName.c_str());
1021 hwc2_config_t activeConfig = 0;
1022 external_display->getActiveConfig(&activeConfig);
1023 external_display->clearDisplay(true);
1024 external_display->setPowerMode(HWC2_POWER_MODE_OFF);
1025 external_display_intf->swapCrtcs(mExynosDisplay);
1026 external_display->mActiveConfig = 0;
1027 external_display->setActiveConfig(activeConfig);
1028 external_display->setPowerMode(HWC2_POWER_MODE_ON);
1029 }
1030 }
1031 }
1032
1033 if (mode == HWC_POWER_MODE_OFF) {
1034 mFBManager.destroyAllSecureBuffers();
1035 }
1036
1037 return ret;
1038 }
1039
setVsyncEnabled(uint32_t enabled)1040 int32_t ExynosDisplayDrmInterface::setVsyncEnabled(uint32_t enabled)
1041 {
1042 if (enabled == HWC2_VSYNC_ENABLE) {
1043 mDrmVSyncWorker.VSyncControl(true);
1044 } else {
1045 if (mVsyncCallback.getDesiredVsyncPeriod() == 0)
1046 mDrmVSyncWorker.VSyncControl(false);
1047 }
1048
1049 mVsyncCallback.enableVSync(HWC2_VSYNC_ENABLE == enabled);
1050
1051 ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
1052 if (exynosDevice->isCallbackAvailable(HWC2_CALLBACK_VSYNC_2_4)) {
1053 DISPLAY_ATRACE_INT(vsyncPeriodTag, 0);
1054 }
1055
1056 return NO_ERROR;
1057 }
1058
choosePreferredConfig()1059 int32_t ExynosDisplayDrmInterface::choosePreferredConfig() {
1060 uint32_t num_configs = 0;
1061 int32_t err = getDisplayConfigs(&num_configs, NULL);
1062 if (err != HWC2_ERROR_NONE || !num_configs)
1063 return err;
1064
1065 int32_t id = -1, fps = 0, vsyncRate = 0, width = 0, height = 0;
1066 err = HWC2_ERROR_BAD_CONFIG;
1067 if ((mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) && (mExynosDisplay->mIndex == 0)) {
1068 char modeStr[PROPERTY_VALUE_MAX];
1069 // kernel preferred mode should be aligned to bootloader setting, use this property
1070 // to specify default user space preferred mode to override kernel's setting.
1071 if (property_get("vendor.display.preferred_mode", modeStr, "") > 0 &&
1072 sscanf(modeStr, "%dx%d@%d", &width, &height, &fps) == 3) {
1073 err = mExynosDisplay->lookupDisplayConfigs(width, height, fps, fps, &id);
1074 } else if (property_get("ro.vendor.primarydisplay.preferred_mode", modeStr, "") > 0 &&
1075 sscanf(modeStr, "%dx%d@%d:%d", &width, &height, &fps, &vsyncRate) == 4) {
1076 err = mExynosDisplay->lookupDisplayConfigs(width, height, fps, vsyncRate, &id);
1077 }
1078 }
1079
1080 const int32_t drmPreferredId = mDrmConnector->get_preferred_mode_id();
1081 if (err != HWC2_ERROR_NONE) {
1082 id = drmPreferredId;
1083 }
1084
1085 auto& configs = mExynosDisplay->mDisplayConfigs;
1086 auto& config = configs[id];
1087 width = config.width;
1088 height = config.height;
1089 fps = config.refreshRate;
1090 vsyncRate = nanoSec2Hz(config.vsyncPeriod);
1091 ALOGI("Preferred mode: configs[%d]=%dx%d@%d:%d, state: %d", id, width, height, fps, vsyncRate,
1092 mDrmConnector->state());
1093 if (id != drmPreferredId &&
1094 (width != configs[drmPreferredId].width || height != configs[drmPreferredId].height)) {
1095 // HWC cannot send a resolution change commit here until 1st frame update because of
1096 // some panels requirement. Therefore, it calls setActiveConfigWithConstraints() help
1097 // set mDesiredModeState correctly, and then trigger modeset in the 1s frame update.
1098 if ((err = setActiveConfigWithConstraints(id)) < 0) {
1099 ALOGE("failed to setActiveConfigWithConstraints(), err %d", err);
1100 return err;
1101 }
1102 } else {
1103 if ((err = setActiveConfig(id)) < 0) {
1104 ALOGE("failed to set default config, err %d", err);
1105 return err;
1106 }
1107 }
1108
1109 return mExynosDisplay->updateInternalDisplayConfigVariables(id);
1110 }
1111
getDisplayConfigs(uint32_t * outNumConfigs,hwc2_config_t * outConfigs)1112 int32_t ExynosDisplayDrmInterface::getDisplayConfigs(
1113 uint32_t* outNumConfigs,
1114 hwc2_config_t* outConfigs)
1115 {
1116 if (!mExynosDisplay || !(mExynosDisplay->mDevice)) {
1117 return HWC2_ERROR_BAD_DISPLAY;
1118 }
1119
1120 std::lock_guard<std::recursive_mutex> lock(mDrmConnector->modesLock());
1121
1122 if (!outConfigs) {
1123 bool useVrrConfigs = isVrrSupported();
1124 int ret = mDrmConnector->UpdateModes(useVrrConfigs);
1125 if (ret < 0) {
1126 ALOGE("%s: failed to update display modes (%d)",
1127 mExynosDisplay->mDisplayName.c_str(), ret);
1128 *outNumConfigs = 0;
1129 return HWC2_ERROR_BAD_DISPLAY;
1130 }
1131 if (ret == 0) {
1132 // no need to update mExynosDisplay->mDisplayConfigs
1133 goto no_mode_changes;
1134 }
1135 ALOGI("Select xRR Config for display %s: %s", mExynosDisplay->mDisplayName.c_str(),
1136 useVrrConfigs ? "VRR" : "MRR");
1137
1138 if (mDrmConnector->state() == DRM_MODE_CONNECTED) {
1139 /*
1140 * EDID property for External Display is created during initialization,
1141 * but it is not complete. It will be completed after Hot Plug Detection
1142 * & DRM Mode update.
1143 */
1144 if (mExynosDisplay->mType == HWC_DISPLAY_EXTERNAL)
1145 mDrmConnector->UpdateEdidProperty();
1146
1147 if (mDrmConnector->modes().size() == 0) {
1148 ALOGE("%s: DRM_MODE_CONNECTED, but no modes available",
1149 mExynosDisplay->mDisplayName.c_str());
1150 mExynosDisplay->mDisplayConfigs.clear();
1151 mExynosDisplay->mPlugState = false;
1152 *outNumConfigs = 0;
1153 return HWC2_ERROR_BAD_DISPLAY;
1154 }
1155
1156 mExynosDisplay->mPlugState = true;
1157 } else
1158 mExynosDisplay->mPlugState = false;
1159
1160 dumpDisplayConfigs();
1161
1162 mExynosDisplay->mDisplayConfigs.clear();
1163
1164 uint32_t mm_width = mDrmConnector->mm_width();
1165 uint32_t mm_height = mDrmConnector->mm_height();
1166 ALOGD("%s: mm_width(%u) mm_height(%u)",
1167 mExynosDisplay->mDisplayName.c_str(), mm_width, mm_height);
1168
1169 DisplayConfigGroupIdGenerator groupIdGenerator;
1170 float peakRr = -1;
1171 for (const DrmMode &mode : mDrmConnector->modes()) {
1172 displayConfigs_t configs;
1173 float rr = mode.v_refresh();
1174 configs.refreshRate = static_cast<int32_t>(rr);
1175 configs.vsyncPeriod = static_cast<int32_t>(mode.te_period());
1176 if (configs.vsyncPeriod <= 0.0f) {
1177 ALOGE("%s:: invalid vsync period", __func__);
1178 return HWC2_ERROR_BAD_DISPLAY;
1179 }
1180 configs.isOperationRateToBts = mode.is_operation_rate_to_bts();
1181 configs.isBoost2xBts = mode.is_boost_2x_bts();
1182 configs.width = mode.h_display();
1183 configs.height = mode.v_display();
1184 // Dots per 1000 inches
1185 configs.Xdpi = mm_width ? (mode.h_display() * kUmPerInch) / mm_width : -1;
1186 // Dots per 1000 inches
1187 configs.Ydpi = mm_height ? (mode.v_display() * kUmPerInch) / mm_height : -1;
1188 // find peak rr
1189 if (rr > peakRr) {
1190 peakRr = rr;
1191 }
1192 configs.isNsMode = mode.is_ns_mode();
1193 // Configure VRR if it's turned on.
1194 if (mXrrSettings.versionInfo.needVrrParameters()) {
1195 VrrConfig_t vrrConfig;
1196 vrrConfig.minFrameIntervalNs = static_cast<int>(std::nano::den / rr);
1197 vrrConfig.vsyncPeriodNs = configs.vsyncPeriod;
1198 configs.vrrConfig = std::make_optional(vrrConfig);
1199 if (mode.is_vrr_mode()) {
1200 if (!isVrrSupported()) {
1201 return HWC2_ERROR_BAD_DISPLAY;
1202 }
1203 configs.vrrConfig->isFullySupported = true;
1204 // TODO(b/290843234): FrameIntervalPowerHint is currently optional and omitted.
1205 // Supply initial values for notifyExpectedPresentConfig; potential changes may
1206 // come later.
1207 NotifyExpectedPresentConfig_t notifyExpectedPresentConfig =
1208 {.HeadsUpNs = mXrrSettings.notifyExpectedPresentConfig.HeadsUpNs,
1209 .TimeoutNs = mXrrSettings.notifyExpectedPresentConfig.TimeoutNs};
1210 configs.vrrConfig->notifyExpectedPresentConfig =
1211 std::make_optional(notifyExpectedPresentConfig);
1212 configs.groupId =
1213 groupIdGenerator.getGroupId(configs.width, configs.height,
1214 configs.vrrConfig->minFrameIntervalNs,
1215 configs.vsyncPeriod);
1216 }
1217 }
1218 if (!mode.is_vrr_mode()) {
1219 configs.groupId = groupIdGenerator.getGroupId(configs.width, configs.height);
1220 }
1221 mExynosDisplay->mDisplayConfigs.insert(std::make_pair(mode.id(), configs));
1222 ALOGD("%s: config group(%d), id(%d), w(%d), h(%d), rr(%f), vsync(%d), "
1223 "xdpi(%d), ydpi(%d), vrr(%s), ns(%s)",
1224 mExynosDisplay->mDisplayName.c_str(), configs.groupId, mode.id(),
1225 configs.width, configs.height, rr, configs.vsyncPeriod,
1226 configs.Xdpi, configs.Ydpi, mode.is_vrr_mode() ? "true" : "false",
1227 mode.is_ns_mode() ? "true" : "false");
1228 }
1229 mExynosDisplay->setPeakRefreshRate(peakRr);
1230 }
1231
1232 no_mode_changes:
1233 uint32_t num_modes = static_cast<uint32_t>(mDrmConnector->modes().size());
1234 if (!outConfigs) {
1235 *outNumConfigs = num_modes;
1236 return (*outNumConfigs > 0) ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_DISPLAY;
1237 }
1238
1239 uint32_t idx = 0;
1240
1241 for (const DrmMode &mode : mDrmConnector->modes()) {
1242 if (idx >= *outNumConfigs)
1243 break;
1244 outConfigs[idx++] = mode.id();
1245 }
1246 *outNumConfigs = idx;
1247
1248 return (*outNumConfigs > 0) ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_DISPLAY;
1249 }
1250
dumpDisplayConfigs()1251 void ExynosDisplayDrmInterface::dumpDisplayConfigs()
1252 {
1253 std::lock_guard<std::recursive_mutex> lock(mDrmConnector->modesLock());
1254
1255 uint32_t num_modes = static_cast<uint32_t>(mDrmConnector->modes().size());
1256 for (uint32_t i = 0; i < num_modes; i++) {
1257 auto mode = mDrmConnector->modes().at(i);
1258 ALOGD("%s: config[%d] %s: id(%d), clock(%d), flags(0x%x), type(0x%x)",
1259 mExynosDisplay->mDisplayName.c_str(), i, mode.name().c_str(), mode.id(),
1260 mode.clock(), mode.flags(), mode.type());
1261 ALOGD("\th_display(%d), h_sync_start(%d), h_sync_end(%d), h_total(%d), h_skew(%d)",
1262 mode.h_display(), mode.h_sync_start(), mode.h_sync_end(), mode.h_total(),
1263 mode.h_skew());
1264 ALOGD("\tv_display(%d), v_sync_start(%d), v_sync_end(%d), v_total(%d), v_scan(%d), "
1265 "v_refresh(%f)",
1266 mode.v_display(), mode.v_sync_start(), mode.v_sync_end(), mode.v_total(),
1267 mode.v_scan(), mode.v_refresh());
1268 }
1269 }
1270
getDisplayVsyncPeriod(hwc2_vsync_period_t * outVsyncPeriod)1271 int32_t ExynosDisplayDrmInterface::getDisplayVsyncPeriod(hwc2_vsync_period_t* outVsyncPeriod)
1272 {
1273 return HWC2_ERROR_UNSUPPORTED;
1274 }
1275
getConfigChangeDuration()1276 int32_t ExynosDisplayDrmInterface::getConfigChangeDuration()
1277 {
1278 const auto [ret, duration] = mDrmConnector->rr_switch_duration().value();
1279
1280 if (!ret && duration > 0) {
1281 return duration;
1282 }
1283
1284 return 2;
1285 };
1286
needRefreshOnLP()1287 bool ExynosDisplayDrmInterface::needRefreshOnLP() {
1288 const auto [ret, refresh_on_lp] = mDrmConnector->refresh_on_lp().value();
1289
1290 if (!ret) {
1291 return refresh_on_lp;
1292 }
1293
1294 return false;
1295 };
1296
getVsyncAppliedTime(hwc2_config_t config,int64_t * actualChangeTime)1297 int32_t ExynosDisplayDrmInterface::getVsyncAppliedTime(
1298 hwc2_config_t config, int64_t* actualChangeTime)
1299 {
1300 if (mDrmCrtc->adjusted_vblank_property().id() == 0) {
1301 uint64_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
1302 *actualChangeTime = currentTime +
1303 (mExynosDisplay->mVsyncPeriod) * getConfigChangeDuration();
1304 return HWC2_ERROR_NONE;
1305 }
1306
1307 int ret = 0;
1308 if ((ret = mDrmDevice->UpdateCrtcProperty(*mDrmCrtc,
1309 &mDrmCrtc->adjusted_vblank_property())) != 0) {
1310 HWC_LOGE(mExynosDisplay, "Failed to update vblank property");
1311 return ret;
1312 }
1313
1314 uint64_t timestamp;
1315 std::tie(ret, timestamp) = mDrmCrtc->adjusted_vblank_property().value();
1316 if (ret < 0) {
1317 HWC_LOGE(mExynosDisplay, "Failed to get vblank property");
1318 return ret;
1319 }
1320
1321 *actualChangeTime = static_cast<int64_t>(timestamp);
1322 return HWC2_ERROR_NONE;
1323 }
1324
supportDataspace(int32_t dataspace)1325 bool ExynosDisplayDrmInterface::supportDataspace(int32_t dataspace)
1326 {
1327 bool supportStandard = false;
1328 bool supportTransfer = false;
1329 bool supportRange = false;
1330
1331 /* Check supported standard */
1332 for (auto &e : mStandardEnums) {
1333 if (e.first & dataspace)
1334 supportStandard = true;
1335 }
1336
1337 /* Check supported transfer */
1338 for (auto &e : mTransferEnums) {
1339 if (e.first & dataspace)
1340 supportTransfer = true;
1341 }
1342
1343 /* Check supported range */
1344 for (auto &e : mRangeEnums) {
1345 if (e.first & dataspace)
1346 supportRange = true;
1347 }
1348
1349 return supportStandard && supportTransfer && supportRange;
1350 }
1351
getColorModes(uint32_t * outNumModes,int32_t * outModes)1352 int32_t ExynosDisplayDrmInterface::getColorModes(uint32_t *outNumModes, int32_t *outModes)
1353 {
1354 if (mDrmCrtc->color_mode_property().id() == 0) {
1355 *outNumModes = 1;
1356
1357 if (outModes != NULL) {
1358 outModes[0] = HAL_COLOR_MODE_NATIVE;
1359 }
1360 return HWC2_ERROR_NONE;
1361 }
1362
1363 uint32_t colorNum = 0;
1364 for (auto &e : mColorModeEnums) {
1365 if (outModes != NULL) {
1366 outModes[colorNum] = e.first;
1367 }
1368 colorNum++;
1369 ALOGD("Colormode [hal: %d, drm: %" PRId64 "]", e.first, e.second);
1370 }
1371 *outNumModes = colorNum;
1372
1373 return HWC2_ERROR_NONE;
1374 }
1375
setColorMode(int32_t mode)1376 int32_t ExynosDisplayDrmInterface::setColorMode(int32_t mode)
1377 {
1378 int ret = 0;
1379
1380 if (mDrmCrtc->color_mode_property().id() == 0) {
1381 return HWC2_ERROR_NONE;
1382 }
1383
1384 DrmModeAtomicReq drmReq(this);
1385
1386 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
1387 mDrmCrtc->color_mode_property(), mode)) < 0)
1388 return ret;
1389
1390 if ((ret = drmReq.commit(0, true)) < 0)
1391 return ret;
1392
1393 return HWC2_ERROR_NONE;
1394 }
1395
setActiveConfigWithConstraints(hwc2_config_t config,bool test)1396 int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints(
1397 hwc2_config_t config, bool test)
1398 {
1399 std::lock_guard<std::recursive_mutex> lock(mDrmConnector->modesLock());
1400
1401 ALOGD("%s:: %s config(%d) test(%d)", __func__, mExynosDisplay->mDisplayName.c_str(), config,
1402 test);
1403
1404 auto mode = std::find_if(mDrmConnector->modes().begin(), mDrmConnector->modes().end(),
1405 [config](DrmMode const &m) { return m.id() == config;});
1406 if (mode == mDrmConnector->modes().end()) {
1407 HWC_LOGE(mExynosDisplay, "Could not find active mode for %d", config);
1408 return HWC2_ERROR_BAD_CONFIG;
1409 }
1410
1411 if (mDesiredModeState.needsModeSet()) {
1412 ALOGI("Previous mode change %d request is not applied", mDesiredModeState.mode.id());
1413 } else if ((mActiveModeState.blob_id != 0) && (mActiveModeState.mode.id() == config)) {
1414 ALOGD("%s:: same mode %d", __func__, config);
1415 /* trigger resetConfigRequestStateLocked() */
1416 mVsyncCallback.setDesiredVsyncPeriod(mActiveModeState.mode.te_period());
1417 mDrmVSyncWorker.VSyncControl(true);
1418 return HWC2_ERROR_NONE;
1419 }
1420
1421 int32_t ret = HWC2_ERROR_NONE;
1422 DrmModeAtomicReq drmReq(this);
1423 uint32_t modeBlob = 0;
1424 if (mDesiredModeState.mode.id() != config) {
1425 if ((ret = createModeBlob(*mode, modeBlob)) != NO_ERROR) {
1426 HWC_LOGE(mExynosDisplay, "%s: Fail to set mode state",
1427 __func__);
1428 return HWC2_ERROR_BAD_CONFIG;
1429 }
1430 }
1431 const auto isResSwitch =
1432 (mActiveModeState.blob_id != 0) && mActiveModeState.isFullModeSwitch(*mode);
1433
1434 if (!test) {
1435 if (modeBlob) { /* only replace desired mode if it has changed */
1436 if (mDesiredModeState.isFullModeSwitch(*mode)) {
1437 mIsResolutionSwitchInProgress = true;
1438 mExynosDisplay->mDevice->setVBlankOffDelay(0);
1439 }
1440 mDesiredModeState.setMode(*mode, modeBlob, drmReq);
1441 if (mExynosDisplay->mOperationRateManager) {
1442 mExynosDisplay->mOperationRateManager->onConfig(config);
1443 mExynosDisplay->handleTargetOperationRate();
1444 }
1445 DISPLAY_DRM_LOGI("%s: config(%d)", __func__, config);
1446 } else {
1447 ALOGD("%s:: same desired mode %d", __func__, config);
1448 }
1449 } else {
1450 if (!isResSwitch) {
1451 ret = setDisplayMode(drmReq, modeBlob ? modeBlob : mDesiredModeState.blob_id,
1452 modeBlob ? mode->id() : mDesiredModeState.mode.id());
1453 if (ret < 0) {
1454 HWC_LOGE(mExynosDisplay, "%s: Fail to apply display mode", __func__);
1455 return ret;
1456 }
1457 ret = drmReq.commit(DRM_MODE_ATOMIC_TEST_ONLY, true);
1458 if (ret) {
1459 drmReq.addOldBlob(modeBlob);
1460 HWC_LOGE(mExynosDisplay,
1461 "%s:: Failed to commit pset ret=%d in applyDisplayMode()\n", __func__,
1462 ret);
1463 return ret;
1464 }
1465 }
1466
1467 if (modeBlob) {
1468 mDrmDevice->DestroyPropertyBlob(modeBlob);
1469 }
1470 }
1471 return HWC2_ERROR_NONE;
1472 }
setActiveDrmMode(DrmMode const & mode)1473 int32_t ExynosDisplayDrmInterface::setActiveDrmMode(DrmMode const &mode) {
1474 /* Don't skip when power was off */
1475 if (!(mExynosDisplay->mSkipFrame) && (mActiveModeState.blob_id != 0) &&
1476 (mActiveModeState.mode.id() == mode.id()) && !mActiveModeState.needsModeSet()) {
1477 ALOGD("%s:: same mode %d", __func__, mode.id());
1478 return HWC2_ERROR_NONE;
1479 }
1480
1481 int32_t ret = HWC2_ERROR_NONE;
1482 uint32_t modeBlob;
1483 if ((ret = createModeBlob(mode, modeBlob)) != NO_ERROR) {
1484 HWC_LOGE(mExynosDisplay, "%s: Fail to set mode state",
1485 __func__);
1486 return HWC2_ERROR_BAD_CONFIG;
1487 }
1488
1489 DrmModeAtomicReq drmReq(this);
1490
1491 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
1492 bool reconfig = false;
1493
1494 if (mActiveModeState.isFullModeSwitch(mode)) {
1495 reconfig = true;
1496 }
1497
1498 if ((ret = setDisplayMode(drmReq, modeBlob, mode.id())) != NO_ERROR) {
1499 drmReq.addOldBlob(modeBlob);
1500 HWC_LOGE(mExynosDisplay, "%s: Fail to apply display mode",
1501 __func__);
1502 return ret;
1503 }
1504
1505 if ((ret = drmReq.commit(flags, true))) {
1506 drmReq.addOldBlob(modeBlob);
1507 HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=%d in applyDisplayMode()\n",
1508 __func__, ret);
1509 return ret;
1510 }
1511
1512 mDrmConnector->set_active_mode(mode);
1513 mActiveModeState.setMode(mode, modeBlob, drmReq);
1514 mActiveModeState.clearPendingModeState();
1515 mVsyncCallback.setVsyncPeriod(mode.te_period());
1516
1517 if (reconfig) {
1518 mDrmConnector->ResetLpMode();
1519 getLowPowerDrmModeModeInfo();
1520 }
1521
1522 return HWC2_ERROR_NONE;
1523 }
1524
setActiveConfig(hwc2_config_t config)1525 int32_t ExynosDisplayDrmInterface::setActiveConfig(hwc2_config_t config) {
1526 std::lock_guard<std::recursive_mutex> lock(mDrmConnector->modesLock());
1527
1528 auto mode = std::find_if(mDrmConnector->modes().begin(), mDrmConnector->modes().end(),
1529 [config](DrmMode const &m) { return m.id() == config; });
1530 if (mode == mDrmConnector->modes().end()) {
1531 HWC_LOGE(mExynosDisplay, "Could not find active mode for %d", config);
1532 return HWC2_ERROR_BAD_CONFIG;
1533 }
1534
1535 if (mExynosDisplay->mOperationRateManager) {
1536 mExynosDisplay->mOperationRateManager->onConfig(config);
1537 mExynosDisplay->handleTargetOperationRate();
1538 }
1539
1540 mExynosDisplay->updateAppliedActiveConfig(config, systemTime(SYSTEM_TIME_MONOTONIC));
1541 if (!setActiveDrmMode(*mode)) {
1542 DISPLAY_DRM_LOGI("%s: config(%d)", __func__, config);
1543 } else {
1544 DISPLAY_DRM_LOGE("%s: config(%d) failed", __func__, config);
1545 }
1546
1547 return 0;
1548 }
1549
createModeBlob(const DrmMode & mode,uint32_t & modeBlob)1550 int32_t ExynosDisplayDrmInterface::createModeBlob(const DrmMode &mode,
1551 uint32_t &modeBlob)
1552 {
1553 struct drm_mode_modeinfo drm_mode;
1554 memset(&drm_mode, 0, sizeof(drm_mode));
1555 mode.ToDrmModeModeInfo(&drm_mode);
1556
1557 modeBlob = 0;
1558 int ret = mDrmDevice->CreatePropertyBlob(&drm_mode, sizeof(drm_mode),
1559 &modeBlob);
1560 if (ret) {
1561 HWC_LOGE(mExynosDisplay, "Failed to create mode property blob %d", ret);
1562 return ret;
1563 }
1564
1565 return NO_ERROR;
1566 }
1567
setDisplayMode(DrmModeAtomicReq & drmReq,const uint32_t & modeBlob,const uint32_t & modeId)1568 int32_t ExynosDisplayDrmInterface::setDisplayMode(DrmModeAtomicReq& drmReq,
1569 const uint32_t& modeBlob,
1570 const uint32_t& modeId) {
1571 int ret = NO_ERROR;
1572
1573 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
1574 mDrmCrtc->active_property(), 1)) < 0)
1575 return ret;
1576
1577 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
1578 mDrmCrtc->mode_property(), modeBlob)) < 0)
1579 return ret;
1580
1581 if ((ret = drmReq.atomicAddProperty(mDrmConnector->id(),
1582 mDrmConnector->crtc_id_property(), mDrmCrtc->id())) < 0)
1583 return ret;
1584
1585 if (mXrrSettings.configChangeCallback) {
1586 drmReq.setAckCallback(std::bind(mXrrSettings.configChangeCallback, modeId));
1587 }
1588
1589 return NO_ERROR;
1590 }
1591
setCursorPositionAsync(uint32_t x_pos,uint32_t y_pos)1592 int32_t ExynosDisplayDrmInterface::setCursorPositionAsync(uint32_t x_pos, uint32_t y_pos)
1593 {
1594 return 0;
1595 }
1596
updateHdrCapabilities()1597 int32_t ExynosDisplayDrmInterface::updateHdrCapabilities()
1598 {
1599 /* Init member variables */
1600 mExynosDisplay->mHdrTypes.clear();
1601 mExynosDisplay->mMaxLuminance = 0;
1602 mExynosDisplay->mMaxAverageLuminance = 0;
1603 mExynosDisplay->mMinLuminance = 0;
1604
1605 if (mExynosDisplay->mType == HWC_DISPLAY_EXTERNAL) {
1606 int upd_res = mDrmConnector->UpdateLuminanceAndHdrProperties();
1607 if (!upd_res) ALOGW("%s: UpdateLuminanceAndHdrProperties failed (%d)", __func__, upd_res);
1608 }
1609 const DrmProperty &prop_max_luminance = mDrmConnector->max_luminance();
1610 const DrmProperty &prop_max_avg_luminance = mDrmConnector->max_avg_luminance();
1611 const DrmProperty &prop_min_luminance = mDrmConnector->min_luminance();
1612 const DrmProperty &prop_hdr_formats = mDrmConnector->hdr_formats();
1613
1614 int ret = 0;
1615 uint64_t max_luminance = 0;
1616 uint64_t max_avg_luminance = 0;
1617 uint64_t min_luminance = 0;
1618 uint64_t hdr_formats = 0;
1619
1620 if ((prop_max_luminance.id() == 0) ||
1621 (prop_max_avg_luminance.id() == 0) ||
1622 (prop_min_luminance.id() == 0) ||
1623 (prop_hdr_formats.id() == 0)) {
1624 HWC_LOGE(mExynosDisplay,
1625 "%s:: there is no property for hdrCapabilities (max_luminance: %d, "
1626 "max_avg_luminance: %d, min_luminance: %d, hdr_formats: %d",
1627 __func__, prop_max_luminance.id(), prop_max_avg_luminance.id(),
1628 prop_min_luminance.id(), prop_hdr_formats.id());
1629 return -1;
1630 }
1631
1632 std::tie(ret, max_luminance) = prop_max_luminance.value();
1633 if (ret < 0) {
1634 HWC_LOGE(mExynosDisplay, "%s:: there is no max_luminance (ret = %d)",
1635 __func__, ret);
1636 return -1;
1637 }
1638 mExynosDisplay->mMaxLuminance = (float)max_luminance / DISPLAY_LUMINANCE_UNIT;
1639
1640 std::tie(ret, max_avg_luminance) = prop_max_avg_luminance.value();
1641 if (ret < 0) {
1642 HWC_LOGE(mExynosDisplay, "%s:: there is no max_avg_luminance (ret = %d)",
1643 __func__, ret);
1644 return -1;
1645 }
1646 mExynosDisplay->mMaxAverageLuminance = (float)max_avg_luminance / DISPLAY_LUMINANCE_UNIT;
1647
1648 std::tie(ret, min_luminance) = prop_min_luminance.value();
1649 if (ret < 0) {
1650 HWC_LOGE(mExynosDisplay, "%s:: there is no min_luminance (ret = %d)",
1651 __func__, ret);
1652 return -1;
1653 }
1654 mExynosDisplay->mMinLuminance = (float)min_luminance / DISPLAY_LUMINANCE_UNIT;
1655
1656 std::tie(ret, hdr_formats) = prop_hdr_formats.value();
1657 if (ret < 0) {
1658 HWC_LOGE(mExynosDisplay, "%s:: there is no hdr_formats (ret = %d)",
1659 __func__, ret);
1660 return -1;
1661 }
1662
1663 uint32_t typeBit;
1664 std::tie(typeBit, ret) = prop_hdr_formats.getEnumValueWithName("Dolby Vision");
1665 if ((ret == 0) && (hdr_formats & (1 << typeBit))) {
1666 mExynosDisplay->mHdrTypes.push_back(HAL_HDR_DOLBY_VISION);
1667 HDEBUGLOGD(eDebugHWC, "%s: supported hdr types : %d",
1668 mExynosDisplay->mDisplayName.c_str(), HAL_HDR_DOLBY_VISION);
1669 }
1670 std::tie(typeBit, ret) = prop_hdr_formats.getEnumValueWithName("HDR10");
1671 if ((ret == 0) && (hdr_formats & (1 << typeBit))) {
1672 mExynosDisplay->mHdrTypes.push_back(HAL_HDR_HDR10);
1673 if (mExynosDisplay->mDevice->mResourceManager->hasHDR10PlusMPP()) {
1674 mExynosDisplay->mHdrTypes.push_back(HAL_HDR_HDR10_PLUS);
1675 }
1676 HDEBUGLOGD(eDebugHWC, "%s: supported hdr types : %d",
1677 mExynosDisplay->mDisplayName.c_str(), HAL_HDR_HDR10);
1678 }
1679 std::tie(typeBit, ret) = prop_hdr_formats.getEnumValueWithName("HLG");
1680 if ((ret == 0) && (hdr_formats & (1 << typeBit))) {
1681 mExynosDisplay->mHdrTypes.push_back(HAL_HDR_HLG);
1682 HDEBUGLOGD(eDebugHWC, "%s: supported hdr types : %d",
1683 mExynosDisplay->mDisplayName.c_str(), HAL_HDR_HLG);
1684 }
1685
1686 ALOGI("%s: get hdrCapabilities info max_luminance(%" PRId64 "), "
1687 "max_avg_luminance(%" PRId64 "), min_luminance(%" PRId64 "), "
1688 "hdr_formats(0x%" PRIx64 ")",
1689 mExynosDisplay->mDisplayName.c_str(),
1690 max_luminance, max_avg_luminance, min_luminance, hdr_formats);
1691
1692 ALOGI("%s: mHdrTypes size(%zu), maxLuminance(%f), maxAverageLuminance(%f), minLuminance(%f)",
1693 mExynosDisplay->mDisplayName.c_str(), mExynosDisplay->mHdrTypes.size(), mExynosDisplay->mMaxLuminance,
1694 mExynosDisplay->mMaxAverageLuminance, mExynosDisplay->mMinLuminance);
1695
1696 return 0;
1697 }
1698
getDeconChannel(ExynosMPP * otfMPP)1699 int ExynosDisplayDrmInterface::getDeconChannel(ExynosMPP *otfMPP)
1700 {
1701 int32_t channelNum = sizeof(idma_channel_map)/sizeof(dpp_channel_map_t);
1702 for (int i = 0; i < channelNum; i++) {
1703 if((idma_channel_map[i].type == otfMPP->mPhysicalType) &&
1704 (idma_channel_map[i].index == otfMPP->mPhysicalIndex))
1705 return idma_channel_map[i].channel;
1706 }
1707 return -EINVAL;
1708 }
1709
setupCommitFromDisplayConfig(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const exynos_win_config_data & config,const uint32_t configIndex,const std::unique_ptr<DrmPlane> & plane,uint32_t & fbId)1710 int32_t ExynosDisplayDrmInterface::setupCommitFromDisplayConfig(
1711 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
1712 const exynos_win_config_data &config,
1713 const uint32_t configIndex,
1714 const std::unique_ptr<DrmPlane> &plane,
1715 uint32_t &fbId)
1716 {
1717 ATRACE_CALL();
1718 int ret = NO_ERROR;
1719
1720 if (fbId == 0) {
1721 if ((ret = mFBManager.getBuffer(config, fbId)) < 0) {
1722 HWC_LOGE(mExynosDisplay, "%s:: Failed to get FB, fbId(%d), ret(%d)", __func__, fbId,
1723 ret);
1724 return ret;
1725 }
1726 }
1727
1728 if ((ret = drmReq.atomicAddProperty(plane->id(),
1729 plane->crtc_property(), mDrmCrtc->id())) < 0)
1730 return ret;
1731 if ((ret = drmReq.atomicAddProperty(plane->id(),
1732 plane->fb_property(), fbId)) < 0)
1733 return ret;
1734 if ((ret = drmReq.atomicAddProperty(plane->id(),
1735 plane->crtc_x_property(), config.dst.x)) < 0)
1736 return ret;
1737 if ((ret = drmReq.atomicAddProperty(plane->id(),
1738 plane->crtc_y_property(), config.dst.y)) < 0)
1739 return ret;
1740 if ((ret = drmReq.atomicAddProperty(plane->id(),
1741 plane->crtc_w_property(), config.dst.w)) < 0)
1742 return ret;
1743 if ((ret = drmReq.atomicAddProperty(plane->id(),
1744 plane->crtc_h_property(), config.dst.h)) < 0)
1745 return ret;
1746 if ((ret = drmReq.atomicAddProperty(plane->id(),
1747 plane->src_x_property(), (int)(config.src.x) << 16)) < 0)
1748 return ret;
1749 if ((ret = drmReq.atomicAddProperty(plane->id(),
1750 plane->src_y_property(), (int)(config.src.y) << 16)) < 0)
1751 HWC_LOGE(mExynosDisplay, "%s:: Failed to add src_y property to plane",
1752 __func__);
1753 if ((ret = drmReq.atomicAddProperty(plane->id(),
1754 plane->src_w_property(), (int)(config.src.w) << 16)) < 0)
1755 return ret;
1756 if ((ret = drmReq.atomicAddProperty(plane->id(),
1757 plane->src_h_property(), (int)(config.src.h) << 16)) < 0)
1758 return ret;
1759
1760 if ((ret = drmReq.atomicAddProperty(plane->id(),
1761 plane->rotation_property(),
1762 halTransformToDrmRot(config.transform), true)) < 0)
1763 return ret;
1764
1765 uint64_t drmEnum = 0;
1766 std::tie(drmEnum, ret) = DrmEnumParser::halToDrmEnum(config.blending, mBlendEnums);
1767 if (ret < 0) {
1768 HWC_LOGE(mExynosDisplay, "Fail to convert blend(%d)", config.blending);
1769 return ret;
1770 }
1771 if ((ret = drmReq.atomicAddProperty(plane->id(),
1772 plane->blend_property(), drmEnum, true)) < 0)
1773 return ret;
1774
1775 if (plane->zpos_property().id() && !plane->zpos_property().isImmutable()) {
1776 uint64_t min_zpos = 0;
1777
1778 // Ignore ret and use min_zpos as 0 by default
1779 std::tie(std::ignore, min_zpos) = plane->zpos_property().rangeMin();
1780
1781 if ((ret = drmReq.atomicAddProperty(plane->id(),
1782 plane->zpos_property(), configIndex + min_zpos)) < 0)
1783 return ret;
1784 }
1785
1786 if (plane->alpha_property().id()) {
1787 uint64_t min_alpha = 0;
1788 uint64_t max_alpha = 0;
1789 std::tie(std::ignore, min_alpha) = plane->alpha_property().rangeMin();
1790 std::tie(std::ignore, max_alpha) = plane->alpha_property().rangeMax();
1791 if ((ret = drmReq.atomicAddProperty(plane->id(),
1792 plane->alpha_property(),
1793 (uint64_t)(((max_alpha - min_alpha) * config.plane_alpha) + 0.5) + min_alpha, true)) < 0)
1794 return ret;
1795 }
1796
1797 if (config.acq_fence >= 0) {
1798 if ((ret = drmReq.atomicAddProperty(plane->id(),
1799 plane->in_fence_fd_property(), config.acq_fence)) < 0)
1800 return ret;
1801 }
1802
1803 if (config.state == config.WIN_STATE_COLOR)
1804 {
1805 if (plane->colormap_property().id()) {
1806 if ((ret = drmReq.atomicAddProperty(plane->id(),
1807 plane->colormap_property(), config.color)) < 0)
1808 return ret;
1809 } else {
1810 HWC_LOGE(mExynosDisplay, "colormap property is not supported");
1811 }
1812 }
1813
1814 std::tie(drmEnum, ret) = DrmEnumParser::halToDrmEnum(
1815 config.dataspace & HAL_DATASPACE_STANDARD_MASK, mStandardEnums);
1816 if (ret < 0) {
1817 HWC_LOGE(mExynosDisplay, "Fail to convert standard(%d)",
1818 config.dataspace & HAL_DATASPACE_STANDARD_MASK);
1819 return ret;
1820 }
1821 if ((ret = drmReq.atomicAddProperty(plane->id(),
1822 plane->standard_property(),
1823 drmEnum, true)) < 0)
1824 return ret;
1825
1826 std::tie(drmEnum, ret) = DrmEnumParser::halToDrmEnum(
1827 config.dataspace & HAL_DATASPACE_TRANSFER_MASK, mTransferEnums);
1828 if (ret < 0) {
1829 HWC_LOGE(mExynosDisplay, "Fail to convert transfer(%d)",
1830 config.dataspace & HAL_DATASPACE_TRANSFER_MASK);
1831 return ret;
1832 }
1833 if ((ret = drmReq.atomicAddProperty(plane->id(),
1834 plane->transfer_property(), drmEnum, true)) < 0)
1835 return ret;
1836
1837 std::tie(drmEnum, ret) = DrmEnumParser::halToDrmEnum(
1838 config.dataspace & HAL_DATASPACE_RANGE_MASK, mRangeEnums);
1839 if (ret < 0) {
1840 HWC_LOGE(mExynosDisplay, "Fail to convert range(%d)",
1841 config.dataspace & HAL_DATASPACE_RANGE_MASK);
1842 return ret;
1843 }
1844 if ((ret = drmReq.atomicAddProperty(plane->id(),
1845 plane->range_property(), drmEnum, true)) < 0)
1846 return ret;
1847
1848 if (hasHdrInfo(config.dataspace)) {
1849 if ((ret = drmReq.atomicAddProperty(plane->id(),
1850 plane->min_luminance_property(), config.min_luminance)) < 0)
1851 return ret;
1852 if ((ret = drmReq.atomicAddProperty(plane->id(),
1853 plane->max_luminance_property(), config.max_luminance)) < 0)
1854 return ret;
1855 }
1856
1857 if (config.state == config.WIN_STATE_RCD) {
1858 if (plane->block_property().id()) {
1859 if (mBlockState != config.block_area) {
1860 uint32_t blobId = 0;
1861 ret = mDrmDevice->CreatePropertyBlob(&config.block_area, sizeof(config.block_area),
1862 &blobId);
1863 if (ret || (blobId == 0)) {
1864 HWC_LOGE(mExynosDisplay, "Failed to create blocking region blob id=%d, ret=%d",
1865 blobId, ret);
1866 return ret;
1867 }
1868
1869 mBlockState.mRegion = config.block_area;
1870 if (mBlockState.mBlobId) {
1871 drmReq.addOldBlob(mBlockState.mBlobId);
1872 }
1873 mBlockState.mBlobId = blobId;
1874 }
1875
1876 if ((ret = drmReq.atomicAddProperty(plane->id(), plane->block_property(),
1877 mBlockState.mBlobId)) < 0) {
1878 HWC_LOGE(mExynosDisplay, "Failed to set blocking region property %d", ret);
1879 return ret;
1880 }
1881 }
1882 }
1883
1884 return NO_ERROR;
1885 }
1886
setupPartialRegion(DrmModeAtomicReq & drmReq)1887 int32_t ExynosDisplayDrmInterface::setupPartialRegion(DrmModeAtomicReq &drmReq)
1888 {
1889 if (!mDrmCrtc->partial_region_property().id())
1890 return NO_ERROR;
1891
1892 int ret = NO_ERROR;
1893
1894 struct decon_frame &update_region = mExynosDisplay->mDpuData.win_update_region;
1895 struct drm_clip_rect partial_rect = {
1896 static_cast<unsigned short>(update_region.x),
1897 static_cast<unsigned short>(update_region.y),
1898 static_cast<unsigned short>(update_region.x + update_region.w),
1899 static_cast<unsigned short>(update_region.y + update_region.h),
1900 };
1901 if ((mPartialRegionState.blob_id == 0) ||
1902 mPartialRegionState.isUpdated(partial_rect))
1903 {
1904 uint32_t blob_id = 0;
1905 ret = mDrmDevice->CreatePropertyBlob(&partial_rect,
1906 sizeof(partial_rect),&blob_id);
1907 if (ret || (blob_id == 0)) {
1908 HWC_LOGE(mExynosDisplay, "Failed to create partial region "
1909 "blob id=%d, ret=%d", blob_id, ret);
1910 return ret;
1911 }
1912
1913 HDEBUGLOGD(eDebugWindowUpdate,
1914 "%s: partial region updated [%d, %d, %d, %d] -> [%d, %d, %d, %d] blob(%d)",
1915 mExynosDisplay->mDisplayName.c_str(),
1916 mPartialRegionState.partial_rect.x1,
1917 mPartialRegionState.partial_rect.y1,
1918 mPartialRegionState.partial_rect.x2,
1919 mPartialRegionState.partial_rect.y2,
1920 partial_rect.x1,
1921 partial_rect.y1,
1922 partial_rect.x2,
1923 partial_rect.y2,
1924 blob_id);
1925 mPartialRegionState.partial_rect = partial_rect;
1926
1927 if (mPartialRegionState.blob_id)
1928 drmReq.addOldBlob(mPartialRegionState.blob_id);
1929 mPartialRegionState.blob_id = blob_id;
1930 }
1931 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
1932 mDrmCrtc->partial_region_property(),
1933 mPartialRegionState.blob_id)) < 0) {
1934 HWC_LOGE(mExynosDisplay, "Failed to set partial region property %d", ret);
1935 return ret;
1936 }
1937
1938 return ret;
1939 }
1940
waitVBlank()1941 int32_t ExynosDisplayDrmInterface::waitVBlank() {
1942 drmVBlank vblank;
1943 uint32_t high_crtc = (mDrmCrtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT);
1944 memset(&vblank, 0, sizeof(vblank));
1945 vblank.request.type = (drmVBlankSeqType)(
1946 DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
1947 vblank.request.sequence = 1;
1948
1949 int ret = drmWaitVBlank(mDrmDevice->fd(), &vblank);
1950 return ret;
1951 }
1952
updateColorSettings(DrmModeAtomicReq & drmReq,uint64_t dqeEnabled)1953 int32_t ExynosDisplayDrmInterface::updateColorSettings(DrmModeAtomicReq &drmReq, uint64_t dqeEnabled) {
1954 int ret = NO_ERROR;
1955
1956 if (dqeEnabled) {
1957 if ((ret = setDisplayColorSetting(drmReq)) != 0) {
1958 HWC_LOGE(mExynosDisplay, "Failed to set display color setting");
1959 return ret;
1960 }
1961 }
1962
1963 for (size_t i = 0; i < mExynosDisplay->mDpuData.configs.size(); i++) {
1964 exynos_win_config_data& config = mExynosDisplay->mDpuData.configs[i];
1965 if ((config.state == config.WIN_STATE_BUFFER) ||
1966 (config.state == config.WIN_STATE_COLOR)) {
1967 int channelId = 0;
1968 if ((channelId = getDeconChannel(config.assignedMPP)) < 0) {
1969 HWC_LOGE(mExynosDisplay, "%s:: Failed to get channel id (%d)",
1970 __func__, channelId);
1971 ret = -EINVAL;
1972 return ret;
1973 }
1974
1975 auto &plane = mDrmDevice->planes().at(channelId);
1976 uint32_t solidColor = config.color;
1977 if ((ret = setPlaneColorSetting(drmReq, plane, config, solidColor)) != 0) {
1978 HWC_LOGE(mExynosDisplay, "Failed to set plane color setting, config[%zu]", i);
1979 return ret;
1980 }
1981 if (config.state == config.WIN_STATE_COLOR && solidColor != config.color) {
1982 config.color = solidColor;
1983 }
1984 }
1985 }
1986
1987 return ret;
1988 }
1989
deliverWinConfigData()1990 int32_t ExynosDisplayDrmInterface::deliverWinConfigData()
1991 {
1992 int ret = NO_ERROR;
1993 DrmModeAtomicReq drmReq(this);
1994 std::unordered_map<uint32_t, uint32_t> planeEnableInfo;
1995 android::String8 result;
1996 bool hasSecureBuffer = false;
1997
1998 mFrameCounter++;
1999
2000 funcReturnCallback retCallback([&]() {
2001 if ((ret == NO_ERROR) && !drmReq.getError()) {
2002 mFBManager.flip(hasSecureBuffer);
2003 } else if (ret == -ENOMEM) {
2004 ALOGW("OOM, release all cached buffers by FBManager");
2005 mFBManager.releaseAll();
2006 }
2007 });
2008
2009 mFBManager.checkShrink();
2010
2011 bool needModesetForReadback = false;
2012 if (mExynosDisplay->mDpuData.enable_readback) {
2013 if ((ret = setupWritebackCommit(drmReq)) < 0) {
2014 HWC_LOGE(mExynosDisplay, "%s:: Failed to setup writeback commit ret(%d)",
2015 __func__, ret);
2016 return ret;
2017 }
2018 needModesetForReadback = true;
2019 } else {
2020 if (mReadbackInfo.mNeedClearReadbackCommit) {
2021 if ((ret = clearWritebackCommit(drmReq)) < 0) {
2022 HWC_LOGE(mExynosDisplay, "%s: Failed to clear writeback commit ret(%d)",
2023 __func__, ret);
2024 return ret;
2025 }
2026 needModesetForReadback = true;
2027 }
2028 }
2029
2030 uint64_t mipi_sync_type = 0;
2031 if (mDesiredModeState.needsModeSet()) {
2032 if (mExynosDisplay->checkRrCompensationEnabled()) {
2033 mipi_sync_type |=
2034 1 << mMipiSyncEnums[toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_REFRESH_RATE)];
2035 }
2036
2037 if ((ret = setDisplayMode(drmReq, mDesiredModeState.blob_id, mDesiredModeState.mode.id())) <
2038 0) {
2039 HWC_LOGE(mExynosDisplay, "%s: Fail to apply display mode",
2040 __func__);
2041 return ret;
2042 }
2043 }
2044
2045 if ((ret = setupPartialRegion(drmReq)) != NO_ERROR)
2046 return ret;
2047
2048 uint64_t out_fences[mDrmDevice->crtcs().size()];
2049 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
2050 mDrmCrtc->out_fence_ptr_property(),
2051 (uint64_t)&out_fences[mDrmCrtc->pipe()], true)) < 0) {
2052 return ret;
2053 }
2054
2055 for (auto &plane : mDrmDevice->planes()) {
2056 planeEnableInfo[plane->id()] = 0;
2057 }
2058
2059 uint64_t dqeEnable = 1;
2060 if (mExynosDisplay->mDpuData.enable_readback &&
2061 !mExynosDisplay->mDpuData.readback_info.requested_from_service) {
2062 dqeEnable = 0;
2063 }
2064
2065 if ((mDrmCrtc->dqe_enabled_property().id()) &&
2066 ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
2067 mDrmCrtc->dqe_enabled_property(), dqeEnable)) < 0)) {
2068 HWC_LOGE(mExynosDisplay, "%s: Fail to dqe_enable setting", __func__);
2069 return ret;
2070 }
2071
2072 // Update of color settings could change layer's solid color. So it should
2073 // be called before use of layer's solid color.
2074 if ((ret = updateColorSettings(drmReq, dqeEnable)) != 0) {
2075 HWC_LOGE(mExynosDisplay, "failed to update color settings (%d)", ret);
2076 return ret;
2077 }
2078
2079 for (size_t i = 0; i < mExynosDisplay->mDpuData.configs.size(); i++) {
2080 exynos_win_config_data& config = mExynosDisplay->mDpuData.configs[i];
2081 if ((config.state == config.WIN_STATE_BUFFER) ||
2082 (config.state == config.WIN_STATE_COLOR)) {
2083 int channelId = 0;
2084 if ((channelId = getDeconChannel(config.assignedMPP)) < 0) {
2085 HWC_LOGE(mExynosDisplay, "%s:: Failed to get channel id (%d)",
2086 __func__, channelId);
2087 ret = -EINVAL;
2088 return ret;
2089 }
2090 /* src size should be set even in dim layer */
2091 if (config.state == config.WIN_STATE_COLOR) {
2092 config.src.w = config.dst.w;
2093 config.src.h = config.dst.h;
2094 }
2095 auto &plane = mDrmDevice->planes().at(channelId);
2096 uint32_t fbId = 0;
2097 if ((ret = setupCommitFromDisplayConfig(drmReq, config, i, plane, fbId)) < 0) {
2098 HWC_LOGE(mExynosDisplay, "setupCommitFromDisplayConfig failed, config[%zu]", i);
2099 return ret;
2100 }
2101 hasSecureBuffer |= config.protection;
2102 /* Set this plane is enabled */
2103 planeEnableInfo[plane->id()] = 1;
2104 }
2105 }
2106
2107 for (size_t i = 0; i < mExynosDisplay->mDpuData.rcdConfigs.size(); ++i) {
2108 exynos_win_config_data &config = mExynosDisplay->mDpuData.rcdConfigs[i];
2109 if ((config.state == config.WIN_STATE_RCD) &&
2110 (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY)) {
2111 const int32_t rcdId = static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId;
2112 const int32_t channelId = getSpecialChannelId(rcdId);
2113 if (channelId >= 0) {
2114 auto &plane = mDrmDevice->planes().at(channelId);
2115 uint32_t fbId = 0;
2116 if ((ret = setupCommitFromDisplayConfig(drmReq, config, i, plane, fbId)) < 0) {
2117 HWC_LOGE(mExynosDisplay, "setupCommitFromDisplayConfig failed, config[%zu]", i);
2118 }
2119 planeEnableInfo[plane->id()] = 1;
2120 }
2121 }
2122 }
2123
2124 /* Disable unused plane */
2125 for (auto &plane : mDrmDevice->planes()) {
2126 if (planeEnableInfo[plane->id()] == 0) {
2127 /* Don't disable planes that are reserved to other display */
2128 ExynosMPP* exynosMPP = mExynosMPPsForPlane[plane->id()];
2129 if ((exynosMPP != NULL) && (mExynosDisplay != NULL) &&
2130 (exynosMPP->mAssignedState & MPP_ASSIGN_STATE_RESERVED) &&
2131 (exynosMPP->mReservedDisplay != (int32_t)mExynosDisplay->mDisplayId))
2132 continue;
2133
2134 if ((exynosMPP == NULL) && (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) &&
2135 (plane->id() != static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId))
2136 continue;
2137
2138 /* If this plane is not supported by the CRTC binded with ExynosDisplay,
2139 * it should be disabled by this ExynosDisplay */
2140 if (!plane->GetCrtcSupported(*mDrmCrtc))
2141 continue;
2142
2143 if ((ret = drmReq.atomicAddProperty(plane->id(),
2144 plane->crtc_property(), 0)) < 0)
2145 return ret;
2146
2147 if ((ret = drmReq.atomicAddProperty(plane->id(),
2148 plane->fb_property(), 0)) < 0)
2149 return ret;
2150 }
2151 }
2152
2153 if (ATRACE_ENABLED()) {
2154 mExynosDisplay->traceLayerTypes();
2155 }
2156
2157 if (mExynosDisplay->mBrightnessController) {
2158 bool ghbmSync, lhbmSync, blSync, opRateSync;
2159 bool mixedComposition = mExynosDisplay->isMixedComposition()
2160 || mExynosDisplay->isPriorFrameMixedCompostion();
2161 ret = mExynosDisplay->mBrightnessController->prepareFrameCommit(*mExynosDisplay,
2162 *mDrmConnector, drmReq,
2163 mixedComposition, ghbmSync,
2164 lhbmSync, blSync,
2165 opRateSync);
2166 if (ret < 0) {
2167 HWC_LOGE(mExynosDisplay, "%s: Fail to config brightness", __func__);
2168 } else {
2169 if (ghbmSync) {
2170 mipi_sync_type |=
2171 1 << mMipiSyncEnums[toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_GHBM)];
2172 }
2173 if (lhbmSync) {
2174 mipi_sync_type |=
2175 1 << mMipiSyncEnums[toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_LHBM)];
2176 }
2177 if (blSync) {
2178 mipi_sync_type |=
2179 1 << mMipiSyncEnums[toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_BL)];
2180 }
2181 if (opRateSync) {
2182 mipi_sync_type |= 1
2183 << mMipiSyncEnums[toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_OP_RATE)];
2184 }
2185 }
2186 }
2187
2188 uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
2189 if (needModesetForReadback || !mDesiredModeState.isSeamless())
2190 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2191
2192 /* For Histogram */
2193 // TODO: b/300026478 - Skip setDisplayHistogramSetting when multi channel is enabled
2194 if (dqeEnable && (ret = setDisplayHistogramSetting(drmReq)) != 0) {
2195 HWC_LOGE(mExynosDisplay, "Failed to set display histogram setting (%d)", ret);
2196 }
2197
2198 /* For multichannel histogram */
2199 if (dqeEnable && mExynosDisplay->mHistogramController) {
2200 mExynosDisplay->mHistogramController->prepareAtomicCommit(drmReq);
2201 }
2202
2203 if (mDrmConnector->mipi_sync().id() && (mipi_sync_type != 0)) {
2204 // skip mipi sync in Doze mode
2205 bool inDoze = isDozeModeAvailable() && mDozeDrmMode.id() == mActiveModeState.mode.id();
2206 if (!inDoze) {
2207 ATRACE_NAME("mipi_sync"); // mark this commit
2208 if ((ret = drmReq.atomicAddProperty(mDrmConnector->id(),
2209 mDrmConnector->mipi_sync(),
2210 mipi_sync_type)) < 0) {
2211 HWC_LOGE(mExynosDisplay, "%s: Fail to set mipi_sync property (%d)", __func__, ret);
2212 }
2213 }
2214 }
2215
2216 auto expectedPresentTime = mExynosDisplay->getPendingExpectedPresentTime();
2217 if (expectedPresentTime != 0) {
2218 /* TODO: don't pass expected present time before we can provide accurate time that desire
2219 * refresh rate take effect (b/202346402)
2220 */
2221 bool ignoreExpectedPresentTime = false;
2222 bool isVrr = mXrrSettings.versionInfo.isVrr();
2223 if (!isVrr && mVsyncCallback.getDesiredVsyncPeriod()) {
2224 ignoreExpectedPresentTime = true;
2225
2226 /* limit the condition to avoid unexpected early present */
2227 auto desiredVsyncPeriod = mVsyncCallback.getDesiredVsyncPeriod();
2228 auto currentVsyncPeriod = mExynosDisplay->mVsyncPeriod;
2229 constexpr auto nsecsPerMs = std::chrono::nanoseconds(1ms).count();
2230 if (currentVsyncPeriod >= desiredVsyncPeriod &&
2231 (((currentVsyncPeriod % desiredVsyncPeriod) < nsecsPerMs) ||
2232 (desiredVsyncPeriod - (currentVsyncPeriod % desiredVsyncPeriod)) < nsecsPerMs)) {
2233 ignoreExpectedPresentTime = false;
2234 }
2235 }
2236
2237 if (!ignoreExpectedPresentTime) {
2238 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
2239 mDrmCrtc->expected_present_time_property(),
2240 expectedPresentTime)) < 0) {
2241 HWC_LOGE(mExynosDisplay, "%s: Fail to set expected_present_time property (%d)",
2242 __func__, ret);
2243 }
2244 }
2245
2246 if (isVrr) {
2247 auto frameInterval = mExynosDisplay->getPendingFrameInterval();
2248 if ((ret = drmReq.atomicAddProperty(mDrmConnector->id(),
2249 mDrmConnector->frame_interval(),
2250 frameInterval)) < 0) {
2251 HWC_LOGE(mExynosDisplay, "%s: Fail to set frameInterval property (%d)",
2252 __func__,
2253 ret);
2254 }
2255 }
2256
2257 mExynosDisplay->applyExpectedPresentTime();
2258 }
2259
2260 if ((ret = drmReq.commit(flags, true)) < 0) {
2261 HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=%d in deliverWinConfigData()\n",
2262 __func__, ret);
2263 mExynosDisplay->setForceColorUpdate(true);
2264 return ret;
2265 }
2266
2267 mExynosDisplay->mDpuData.retire_fence = (int)out_fences[mDrmCrtc->pipe()];
2268 /*
2269 * [HACK] dup retire_fence for each layer's release fence
2270 * Do not use hwc_dup because hwc_dup increase usage count of fence treacer
2271 * Usage count of this fence is incresed by ExynosDisplay::deliverWinConfigData()
2272 */
2273 for (auto &display_config : mExynosDisplay->mDpuData.configs) {
2274 if ((display_config.state == display_config.WIN_STATE_BUFFER) ||
2275 (display_config.state == display_config.WIN_STATE_CURSOR)) {
2276 display_config.rel_fence =
2277 dup((int)out_fences[mDrmCrtc->pipe()]);
2278 }
2279 }
2280
2281 if (mDesiredModeState.needsModeSet()) {
2282 mDesiredModeState.apply(mActiveModeState, drmReq);
2283 if (!mActiveModeState.isSeamless()) {
2284 mDrmConnector->ResetLpMode();
2285 getLowPowerDrmModeModeInfo();
2286 }
2287 mVsyncCallback.setDesiredVsyncPeriod(mActiveModeState.mode.te_period());
2288 mVsyncCallback.setModeSetFence(dup(mExynosDisplay->mDpuData.retire_fence));
2289 /* Enable vsync to check vsync period */
2290 mDrmVSyncWorker.VSyncControl(true);
2291 }
2292
2293 /* For multichannel histogram */
2294 if (dqeEnable && mExynosDisplay->mHistogramController) {
2295 mExynosDisplay->mHistogramController->postAtomicCommit();
2296 }
2297
2298 return NO_ERROR;
2299 }
2300
clearDisplayMode(DrmModeAtomicReq & drmReq)2301 int32_t ExynosDisplayDrmInterface::clearDisplayMode(DrmModeAtomicReq &drmReq)
2302 {
2303 int ret = NO_ERROR;
2304
2305 if ((ret = drmReq.atomicAddProperty(mDrmConnector->id(),
2306 mDrmConnector->crtc_id_property(), 0)) < 0)
2307 return ret;
2308
2309 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
2310 mDrmCrtc->mode_property(), 0)) < 0)
2311 return ret;
2312
2313 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
2314 mDrmCrtc->active_property(), 0)) < 0)
2315 return ret;
2316
2317 return NO_ERROR;
2318 }
2319
triggerClearDisplayPlanes()2320 int32_t ExynosDisplayDrmInterface::triggerClearDisplayPlanes()
2321 {
2322 ATRACE_CALL();
2323 DrmModeAtomicReq drmReq(this);
2324
2325 clearDisplayPlanes(drmReq);
2326 int ret = NO_ERROR;
2327 if ((ret = drmReq.commit(0, true))) {
2328 HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=(%d)\n",
2329 __func__, ret);
2330 return ret;
2331 }
2332 return ret;
2333 }
2334
setXrrSettings(const XrrSettings_t & settings)2335 void ExynosDisplayDrmInterface::setXrrSettings(const XrrSettings_t& settings) {
2336 mXrrSettings = settings;
2337 }
2338
clearDisplayPlanes(DrmModeAtomicReq & drmReq)2339 int32_t ExynosDisplayDrmInterface::clearDisplayPlanes(DrmModeAtomicReq &drmReq)
2340 {
2341 int ret = NO_ERROR;
2342
2343 /* Disable all planes */
2344 for (auto &plane : mDrmDevice->planes()) {
2345 /* Do not disable planes that are reserved to other dispaly */
2346 ExynosMPP* exynosMPP = mExynosMPPsForPlane[plane->id()];
2347 if ((exynosMPP != NULL) && (mExynosDisplay != NULL) &&
2348 (exynosMPP->mAssignedState & MPP_ASSIGN_STATE_RESERVED) &&
2349 (exynosMPP->mReservedDisplay != (int32_t)mExynosDisplay->mDisplayId))
2350 continue;
2351
2352 /* If this plane is not supported by the CRTC binded with ExynosDisplay,
2353 * it should be disabled by this ExynosDisplay */
2354 if (!plane->GetCrtcSupported(*mDrmCrtc))
2355 continue;
2356
2357 if ((ret = drmReq.atomicAddProperty(plane->id(),
2358 plane->crtc_property(), 0)) < 0) {
2359 break;
2360 }
2361
2362 if ((ret = drmReq.atomicAddProperty(plane->id(),
2363 plane->fb_property(), 0)) < 0) {
2364 break;
2365 }
2366 }
2367
2368 return ret;
2369 }
2370
clearDisplay(bool needModeClear)2371 int32_t ExynosDisplayDrmInterface::clearDisplay(bool needModeClear)
2372 {
2373 ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
2374 const bool isAsyncOff = needModeClear && exynosDevice->isDispOffAsyncSupported() &&
2375 !exynosDevice->hasOtherDisplayOn(mExynosDisplay) && !mIsFirstClean;
2376 if (mIsFirstClean) {
2377 mIsFirstClean = false;
2378 ALOGI("%s: first clean == true", __func__);
2379 }
2380 int ret = NO_ERROR;
2381 DrmModeAtomicReq drmReq(this);
2382
2383 ret = clearDisplayPlanes(drmReq);
2384 if (ret != NO_ERROR) {
2385 HWC_LOGE(mExynosDisplay, "%s: Failed to clear planes", __func__);
2386
2387 return ret;
2388 }
2389
2390 /* Disable readback connector if required */
2391 if (mReadbackInfo.mNeedClearReadbackCommit &&
2392 !mExynosDisplay->mDpuData.enable_readback) {
2393 if ((ret = clearWritebackCommit(drmReq)) < 0) {
2394 HWC_LOGE(mExynosDisplay, "%s: Failed to apply writeback", __func__);
2395 return ret;
2396 }
2397 }
2398
2399 /* Disable ModeSet */
2400 if (needModeClear && !isAsyncOff) {
2401 if ((ret = clearDisplayMode(drmReq)) < 0) {
2402 HWC_LOGE(mExynosDisplay, "%s: Failed to apply display mode", __func__);
2403 return ret;
2404 }
2405 }
2406
2407 ret = drmReq.commit(DRM_MODE_ATOMIC_ALLOW_MODESET, true);
2408 if (ret) {
2409 HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=%d in clearDisplay()\n",
2410 __func__, ret);
2411 return ret;
2412 }
2413
2414 /* During async off we're clearing planes within a single refresh cycle
2415 * and then offloading display off asynchronously.
2416 */
2417 if (isAsyncOff) {
2418 if ((ret = clearDisplayMode(drmReq)) < 0) {
2419 HWC_LOGE(mExynosDisplay, "%s: Failed to apply display mode", __func__);
2420 return ret;
2421 }
2422
2423 ret = drmReq.commit(DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_NONBLOCK, true);
2424 if (ret) {
2425 HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=%d in clearDisplay()\n",
2426 __func__, ret);
2427 return ret;
2428 }
2429 }
2430
2431 if (needModeClear) mActiveModeState.forceModeSet();
2432
2433 return NO_ERROR;
2434 }
2435
disableSelfRefresh(uint32_t disable)2436 int32_t ExynosDisplayDrmInterface::disableSelfRefresh(uint32_t disable)
2437 {
2438 return 0;
2439 }
2440
setForcePanic()2441 int32_t ExynosDisplayDrmInterface::setForcePanic()
2442 {
2443 if (exynosHWCControl.forcePanic == 0)
2444 return NO_ERROR;
2445
2446 usleep(20000000);
2447
2448 FILE *forcePanicFd = fopen(HWC_FORCE_PANIC_PATH, "w");
2449 if (forcePanicFd == NULL) {
2450 ALOGW("%s:: Failed to open fd", __func__);
2451 return -1;
2452 }
2453
2454 int val = 1;
2455 fwrite(&val, sizeof(int), 1, forcePanicFd);
2456 fclose(forcePanicFd);
2457
2458 return 0;
2459 }
2460
DrmModeAtomicReq(ExynosDisplayDrmInterface * displayInterface)2461 ExynosDisplayDrmInterface::DrmModeAtomicReq::DrmModeAtomicReq(ExynosDisplayDrmInterface *displayInterface)
2462 : mDrmDisplayInterface(displayInterface)
2463 {
2464 mPset = drmModeAtomicAlloc();
2465 mSavedPset = NULL;
2466 }
2467
~DrmModeAtomicReq()2468 ExynosDisplayDrmInterface::DrmModeAtomicReq::~DrmModeAtomicReq()
2469 {
2470 if (mError != 0) {
2471 android::String8 result;
2472 result.appendFormat("atomic commit error\n");
2473 if (hwcCheckDebugMessages(eDebugDisplayInterfaceConfig) == false)
2474 dumpAtomicCommitInfo(result);
2475 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay, "%s", result.c_str());
2476 }
2477
2478 if(mPset)
2479 drmModeAtomicFree(mPset);
2480
2481 if (destroyOldBlobs() != NO_ERROR)
2482 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay, "destroy blob error");
2483 }
2484
atomicAddProperty(const uint32_t id,const DrmProperty & property,uint64_t value,bool optional)2485 int32_t ExynosDisplayDrmInterface::DrmModeAtomicReq::atomicAddProperty(
2486 const uint32_t id,
2487 const DrmProperty &property,
2488 uint64_t value, bool optional)
2489 {
2490 if (!optional && !property.id()) {
2491 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay, "%s:: %s property id(%d) for id(%d) is not available",
2492 __func__, property.name().c_str(), property.id(), id);
2493 return -EINVAL;
2494 }
2495
2496 if (property.id() && property.validateChange(value)) {
2497 int ret = drmModeAtomicAddProperty(mPset, id,
2498 property.id(), value);
2499 if (ret < 0) {
2500 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay, "%s:: Failed to add property %d(%s) for id(%d), ret(%d)",
2501 __func__, property.id(), property.name().c_str(), id, ret);
2502 return ret;
2503 }
2504 }
2505
2506 return NO_ERROR;
2507 }
2508
dumpAtomicCommitInfo(String8 & result,bool debugPrint)2509 String8& ExynosDisplayDrmInterface::DrmModeAtomicReq::dumpAtomicCommitInfo(
2510 String8 &result, bool debugPrint)
2511 {
2512 /* print log only if eDebugDisplayInterfaceConfig flag is set when debugPrint is true */
2513 if (debugPrint &&
2514 (hwcCheckDebugMessages(eDebugDisplayInterfaceConfig) == false))
2515 return result;
2516
2517 if (debugPrint)
2518 ALOGD("%s atomic config ++++++++++++", mDrmDisplayInterface->mExynosDisplay->mDisplayName.c_str());
2519
2520 for (int i = 0; i < drmModeAtomicGetCursor(mPset); i++) {
2521 const DrmProperty *property = NULL;
2522 String8 objectName;
2523 /* Check crtc properties */
2524 if (mPset->items[i].object_id == mDrmDisplayInterface->mDrmCrtc->id()) {
2525 for (auto property_ptr : mDrmDisplayInterface->mDrmCrtc->properties()) {
2526 if (mPset->items[i].property_id == property_ptr->id()){
2527 property = property_ptr;
2528 objectName.appendFormat("Crtc");
2529 break;
2530 }
2531 }
2532 if (property == NULL) {
2533 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay,
2534 "%s:: object id is crtc but there is no matched property",
2535 __func__);
2536 }
2537 } else if (mPset->items[i].object_id == mDrmDisplayInterface->mDrmConnector->id()) {
2538 for (auto property_ptr : mDrmDisplayInterface->mDrmConnector->properties()) {
2539 if (mPset->items[i].property_id == property_ptr->id()){
2540 property = property_ptr;
2541 objectName.appendFormat("Connector");
2542 break;
2543 }
2544 }
2545 if (property == NULL) {
2546 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay,
2547 "%s:: object id is connector but there is no matched property",
2548 __func__);
2549 }
2550 } else {
2551 uint32_t channelId = 0;
2552 for (auto &plane : mDrmDisplayInterface->mDrmDevice->planes()) {
2553 if (mPset->items[i].object_id == plane->id()) {
2554 for (auto property_ptr : plane->properties()) {
2555 if (mPset->items[i].property_id == property_ptr->id()){
2556 property = property_ptr;
2557 objectName.appendFormat("Plane[%d]", channelId);
2558 break;
2559 }
2560 }
2561 if (property == NULL) {
2562 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay,
2563 "%s:: object id is plane but there is no matched property",
2564 __func__);
2565 }
2566 }
2567 channelId++;
2568 }
2569 }
2570 if (property == NULL) {
2571 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay,
2572 "%s:: Fail to get property[%d] (object_id: %d, property_id: %d, value: %" PRId64 ")",
2573 __func__, i, mPset->items[i].object_id, mPset->items[i].property_id,
2574 mPset->items[i].value);
2575 continue;
2576 }
2577
2578 if (debugPrint)
2579 ALOGD("property[%d] %s object_id: %d, property_id: %d, name: %s, value: %" PRId64 ")\n",
2580 i, objectName.c_str(), mPset->items[i].object_id, mPset->items[i].property_id, property->name().c_str(), mPset->items[i].value);
2581 else
2582 result.appendFormat("property[%d] %s object_id: %d, property_id: %d, name: %s, value: %" PRId64 ")\n",
2583 i, objectName.c_str(), mPset->items[i].object_id, mPset->items[i].property_id, property->name().c_str(), mPset->items[i].value);
2584 }
2585 return result;
2586 }
2587
commit(uint32_t flags,bool loggingForDebug)2588 int ExynosDisplayDrmInterface::DrmModeAtomicReq::commit(uint32_t flags, bool loggingForDebug)
2589 {
2590 ATRACE_NAME("drmModeAtomicCommit");
2591 android::String8 result;
2592
2593 /*
2594 * During kernel is in TUI, all atomic commits should be returned with error EPERM(-1).
2595 * To avoid handling atomic commit as fail, it needs to check TUI status.
2596 */
2597 int ret = drmModeAtomicCommit(mDrmDisplayInterface->mDrmDevice->fd(),
2598 mPset, flags, mDrmDisplayInterface->mDrmDevice);
2599 if (loggingForDebug)
2600 dumpAtomicCommitInfo(result, true);
2601 if ((ret == -EPERM) && mDrmDisplayInterface->mDrmDevice->event_listener()->IsDrmInTUI()) {
2602 ALOGV("skip atomic commit error handling as kernel is in TUI");
2603 ret = NO_ERROR;
2604 } else if (ret < 0) {
2605 if (ret == -EINVAL) {
2606 dumpDrmAtomicCommitMessage(ret);
2607 }
2608 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay, "commit error: %d", ret);
2609 setError(ret);
2610 }
2611
2612 if (ret == 0 && mAckCallback) {
2613 if (!(flags & DRM_MODE_ATOMIC_TEST_ONLY)) {
2614 mAckCallback();
2615 }
2616 }
2617
2618 if (mDrmDisplayInterface->mIsResolutionSwitchInProgress &&
2619 !mDrmDisplayInterface->mDesiredModeState.needsModeSet()) {
2620 mDrmDisplayInterface->mIsResolutionSwitchInProgress = false;
2621 mDrmDisplayInterface->mExynosDisplay->mDevice->setVBlankOffDelay(1);
2622 }
2623
2624 return ret;
2625 }
2626
dumpDrmAtomicCommitMessage(int err)2627 void ExynosDisplayDrmInterface::DrmModeAtomicReq::dumpDrmAtomicCommitMessage(int err) {
2628 const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
2629 const nsecs_t diffMs = ns2ms(now - mDrmDisplayInterface->mLastDumpDrmAtomicMessageTime);
2630 if (diffMs < kAllowDumpDrmAtomicMessageTimeMs) {
2631 return;
2632 }
2633
2634 if (writeIntToKernelFile(kDrmModuleParametersDebugNode, kEnableDrmAtomicMessage)) {
2635 return;
2636 }
2637
2638 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay,
2639 "commit error, enable atomic message and test again");
2640 int ret = drmModeAtomicCommit(mDrmDisplayInterface->mDrmDevice->fd(), mPset,
2641 DRM_MODE_ATOMIC_TEST_ONLY, mDrmDisplayInterface->mDrmDevice);
2642 if (ret != err) {
2643 HWC_LOGE(mDrmDisplayInterface->mExynosDisplay,
2644 "re-try commit error(%d) is different from %d", ret, err);
2645 }
2646
2647 writeIntToKernelFile(kDrmModuleParametersDebugNode, kDisableDrmDebugMessage);
2648 mDrmDisplayInterface->mLastDumpDrmAtomicMessageTime = systemTime(SYSTEM_TIME_MONOTONIC);
2649 }
2650
getReadbackBufferAttributes(int32_t * outFormat,int32_t * outDataspace)2651 int32_t ExynosDisplayDrmInterface::getReadbackBufferAttributes(
2652 int32_t* /*android_pixel_format_t*/ outFormat,
2653 int32_t* /*android_dataspace_t*/ outDataspace)
2654 {
2655 DrmConnector *writeback_conn = mReadbackInfo.getWritebackConnector();
2656 if (writeback_conn == NULL) {
2657 ALOGE("%s: There is no writeback connection", __func__);
2658 return -EINVAL;
2659 }
2660 mReadbackInfo.pickFormatDataspace();
2661 if (mReadbackInfo.mReadbackFormat ==
2662 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
2663 ALOGE("readback format(%d) is not valid",
2664 mReadbackInfo.mReadbackFormat);
2665 return -EINVAL;
2666 }
2667 *outFormat = mReadbackInfo.mReadbackFormat;
2668 *outDataspace = HAL_DATASPACE_UNKNOWN;
2669 return NO_ERROR;
2670 }
2671
setupWritebackCommit(DrmModeAtomicReq & drmReq)2672 int32_t ExynosDisplayDrmInterface::setupWritebackCommit(DrmModeAtomicReq &drmReq)
2673 {
2674 int ret = NO_ERROR;
2675 DrmConnector *writeback_conn = mReadbackInfo.getWritebackConnector();
2676 if (writeback_conn == NULL) {
2677 ALOGE("%s: There is no writeback connection", __func__);
2678 return -EINVAL;
2679 }
2680 if (writeback_conn->writeback_fb_id().id() == 0 ||
2681 writeback_conn->writeback_out_fence().id() == 0) {
2682 ALOGE("%s: Writeback properties don't exit", __func__);
2683 return -EINVAL;
2684 }
2685
2686 uint32_t writeback_fb_id = 0;
2687 exynos_win_config_data writeback_config;
2688 VendorGraphicBufferMeta gmeta(mExynosDisplay->mDpuData.readback_info.handle);
2689
2690 writeback_config.state = exynos_win_config_data::WIN_STATE_BUFFER;
2691 writeback_config.format = mReadbackInfo.mReadbackFormat;
2692 writeback_config.src = {0, 0, mExynosDisplay->mXres, mExynosDisplay->mYres,
2693 gmeta.stride, gmeta.vstride};
2694 writeback_config.dst = {0, 0, mExynosDisplay->mXres, mExynosDisplay->mYres,
2695 gmeta.stride, gmeta.vstride};
2696 writeback_config.fd_idma[0] = gmeta.fd;
2697 writeback_config.fd_idma[1] = gmeta.fd1;
2698 writeback_config.fd_idma[2] = gmeta.fd2;
2699 if ((ret = mFBManager.getBuffer(writeback_config, writeback_fb_id)) < 0) {
2700 ALOGE("%s: getBuffer() fail ret(%d)", __func__, ret);
2701 return ret;
2702 }
2703
2704 if ((ret = drmReq.atomicAddProperty(writeback_conn->id(),
2705 writeback_conn->writeback_fb_id(),
2706 writeback_fb_id)) < 0)
2707 return ret;
2708
2709 if ((ret = drmReq.atomicAddProperty(writeback_conn->id(),
2710 writeback_conn->writeback_out_fence(),
2711 (uint64_t)& mExynosDisplay->mDpuData.readback_info.acq_fence)) < 0)
2712 return ret;
2713
2714 if ((ret = drmReq.atomicAddProperty(writeback_conn->id(),
2715 writeback_conn->crtc_id_property(),
2716 mDrmCrtc->id())) < 0)
2717 return ret;
2718
2719 mReadbackInfo.setFbId(writeback_fb_id);
2720 mReadbackInfo.mNeedClearReadbackCommit = true;
2721 return NO_ERROR;
2722 }
2723
clearWritebackCommit(DrmModeAtomicReq & drmReq)2724 int32_t ExynosDisplayDrmInterface::clearWritebackCommit(DrmModeAtomicReq &drmReq)
2725 {
2726 int ret;
2727
2728 DrmConnector *writeback_conn = mReadbackInfo.getWritebackConnector();
2729 if (writeback_conn == NULL) {
2730 ALOGE("%s: There is no writeback connection", __func__);
2731 return -EINVAL;
2732 }
2733
2734 if ((ret = drmReq.atomicAddProperty(writeback_conn->id(),
2735 writeback_conn->writeback_fb_id(), 0)) < 0)
2736 return ret;
2737
2738 if ((ret = drmReq.atomicAddProperty(writeback_conn->id(),
2739 writeback_conn->writeback_out_fence(), 0)) < 0)
2740 return ret;
2741
2742 if ((ret = drmReq.atomicAddProperty(writeback_conn->id(),
2743 writeback_conn->crtc_id_property(), 0)) < 0)
2744 return ret;
2745
2746 mReadbackInfo.mNeedClearReadbackCommit = false;
2747 return NO_ERROR;
2748 }
2749
init(DrmDevice * drmDevice,uint32_t displayId)2750 void ExynosDisplayDrmInterface::DrmReadbackInfo::init(DrmDevice *drmDevice, uint32_t displayId)
2751 {
2752 mDrmDevice = drmDevice;
2753 mWritebackConnector = mDrmDevice->AvailableWritebackConnector(displayId);
2754 if (mWritebackConnector == NULL) {
2755 ALOGI("writeback is not supported");
2756 return;
2757 }
2758 if (mWritebackConnector->writeback_fb_id().id() == 0 ||
2759 mWritebackConnector->writeback_out_fence().id() == 0) {
2760 ALOGE("%s: Writeback properties don't exit", __func__);
2761 mWritebackConnector = NULL;
2762 return;
2763 }
2764
2765 if (mWritebackConnector->writeback_pixel_formats().id()) {
2766 int32_t ret = NO_ERROR;
2767 uint64_t blobId;
2768 std::tie(ret, blobId) = mWritebackConnector->writeback_pixel_formats().value();
2769 if (ret) {
2770 ALOGE("Fail to get blob id for writeback_pixel_formats");
2771 return;
2772 }
2773 drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(mDrmDevice->fd(), blobId);
2774 if (!blob) {
2775 ALOGE("Fail to get blob for writeback_pixel_formats(%" PRId64 ")", blobId);
2776 return;
2777 }
2778 uint32_t formatNum = (blob->length)/sizeof(uint32_t);
2779 uint32_t *formats = (uint32_t *)blob->data;
2780 for (uint32_t i = 0; i < formatNum; i++) {
2781 int halFormat = drmFormatToHalFormat(formats[i]);
2782 ALOGD("supported writeback format[%d] %4.4s, %d", i, (char *)&formats[i], halFormat);
2783 if (halFormat != HAL_PIXEL_FORMAT_EXYNOS_UNDEFINED)
2784 mSupportedFormats.push_back(halFormat);
2785 }
2786 drmModeFreePropertyBlob(blob);
2787 }
2788 }
2789
pickFormatDataspace()2790 void ExynosDisplayDrmInterface::DrmReadbackInfo::pickFormatDataspace()
2791 {
2792 if (!mSupportedFormats.empty())
2793 mReadbackFormat = mSupportedFormats[0];
2794 auto it = std::find(mSupportedFormats.begin(),
2795 mSupportedFormats.end(), PREFERRED_READBACK_FORMAT);
2796 if (it != mSupportedFormats.end())
2797 mReadbackFormat = *it;
2798 }
2799
getDisplayFakeEdid(uint8_t & outPort,uint32_t & outDataSize,uint8_t * outData)2800 int32_t ExynosDisplayDrmInterface::getDisplayFakeEdid(uint8_t &outPort, uint32_t &outDataSize,
2801 uint8_t *outData) {
2802 uint32_t width = mExynosDisplay->mXres;
2803 uint32_t height = mExynosDisplay->mYres;
2804 uint32_t clock = (width * height * kDefaultRefreshRateFrequency) / 10000;
2805 std::array<uint8_t, 128> edid_buf{
2806 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, /* header */
2807 0x1C, 0xEC, /* manufacturer GGL */
2808 0x00, 0x00, /* product */
2809 0x00, 0x00, 0x00, 0x00, /* serial number */
2810 0x01, /* week of manufacture */
2811 0x00, /* year of manufacture */
2812 0x01, 0x03, /* EDID version */
2813 0x80, /* capabilities - digital */
2814 0x00, /* horizontal in cm */
2815 0x00, /* vertical in cm */
2816 0x78, /* gamma 2.2 */
2817 0xEE, 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54, /* chromaticity */
2818 0x00, 0x00, 0x00, /* no default timings */
2819 /* no standard timings */
2820 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
2821 0x01, 0x01,
2822 /* descriptor block 1 */
2823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2824 0x00, 0x00, 0x00, 0x00,
2825 /* descriptor block 2 */
2826 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20,
2827 0x20, 0x20, 0x20, 0x20,
2828 /* descriptor block 3 */
2829 0x00, 0x00, 0x00, 0xFC, 0x00, 'C', 'o', 'm', 'm', 'o', 'n', ' ', 'P', 'a', 'n', 'e',
2830 'l', '\n',
2831 /* descriptor block 4 */
2832 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2833 0x00, 0x00, 0x00, 0x00, 0x00, /* number of extensions */
2834 0x00 /* checksum */
2835 };
2836 edid_buf[55] = clock >> 8;
2837 edid_buf[56] = width & 0xff;
2838 edid_buf[58] = (width >> 4) & 0xf0;
2839 edid_buf[59] = height & 0xff;
2840 edid_buf[61] = (height >> 4) & 0xf0;
2841
2842 if (mMonitorDescription[0] != 0) {
2843 /* Descriptor block 3 starts at address 90, data offset is 5 bytes */
2844 memcpy(&edid_buf[95], mMonitorDescription.data(), mMonitorDescription.size());
2845 }
2846
2847 unsigned int sum = std::accumulate(edid_buf.begin(), edid_buf.end() - 1, 0);
2848 edid_buf[127] = (0x100 - (sum & 0xFF)) & 0xFF;
2849 if (outData) {
2850 outDataSize = std::min<uint32_t>(outDataSize, edid_buf.size());
2851 memcpy(outData, edid_buf.data(), outDataSize);
2852 } else {
2853 outDataSize = static_cast<uint32_t>(edid_buf.size());
2854 }
2855
2856 outPort = mExynosDisplay->mDisplayId;
2857 ALOGD("using Display Fake Edid");
2858 return HWC2_ERROR_NONE;
2859 }
2860
getDisplayIdentificationData(uint8_t * outPort,uint32_t * outDataSize,uint8_t * outData)2861 int32_t ExynosDisplayDrmInterface::getDisplayIdentificationData(
2862 uint8_t* outPort, uint32_t* outDataSize, uint8_t* outData)
2863 {
2864 if ((mDrmDevice == nullptr) || (mDrmConnector == nullptr)) {
2865 ALOGE("%s: display(%s) mDrmDevice(%p), mDrmConnector(%p)",
2866 __func__, mExynosDisplay->mDisplayName.c_str(),
2867 mDrmDevice, mDrmConnector);
2868 return HWC2_ERROR_UNSUPPORTED;
2869 }
2870
2871 if (mDrmConnector->edid_property().id() == 0) {
2872 ALOGD("%s: edid_property is not supported",
2873 mExynosDisplay->mDisplayName.c_str());
2874 return HWC2_ERROR_UNSUPPORTED;
2875 }
2876
2877 if (outPort == nullptr || outDataSize == nullptr) return HWC2_ERROR_BAD_PARAMETER;
2878
2879 drmModePropertyBlobPtr blob;
2880 int ret;
2881 uint64_t blobId;
2882
2883 std::tie(ret, blobId) = mDrmConnector->edid_property().value();
2884 if (ret) {
2885 ALOGE("Failed to get edid property value.");
2886 return HWC2_ERROR_UNSUPPORTED;
2887 }
2888 if (blobId == 0) {
2889 ALOGD("%s: edid_property is supported but blob is not valid",
2890 mExynosDisplay->mDisplayName.c_str());
2891 return getDisplayFakeEdid(*outPort, *outDataSize, outData);
2892 }
2893
2894 blob = drmModeGetPropertyBlob(mDrmDevice->fd(), blobId);
2895 if (blob == nullptr) {
2896 ALOGD("%s: Failed to get blob",
2897 mExynosDisplay->mDisplayName.c_str());
2898 return HWC2_ERROR_UNSUPPORTED;
2899 }
2900
2901 if (outData) {
2902 *outDataSize = std::min(*outDataSize, blob->length);
2903 memcpy(outData, blob->data, *outDataSize);
2904 setManufacturerInfo(outData[kEDIDManufacturerIDByte1], outData[kEDIDManufacturerIDByte2]);
2905 setProductId(outData[kEDIDProductIDByte1], outData[kEDIDProductIDByte2]);
2906 } else {
2907 *outDataSize = blob->length;
2908 }
2909 drmModeFreePropertyBlob(blob);
2910 *outPort = mDrmConnector->id();
2911
2912 return HWC2_ERROR_NONE;
2913 }
2914
getSpecialChannelId(uint32_t planeId)2915 int32_t ExynosDisplayDrmInterface::getSpecialChannelId(uint32_t planeId) {
2916 ExynosDevice *exynosDevice = mExynosDisplay->mDevice;
2917 for (int i = 0; i < exynosDevice->getSpecialPlaneNum(); i++) {
2918 const int32_t channelId = exynosDevice->getSpecialPlaneId(i);
2919 auto &plane = mDrmDevice->planes().at(channelId);
2920 if (plane->id() == planeId) return channelId;
2921 }
2922
2923 ALOGE("%s: Failed to get RCD planeId.", __func__);
2924
2925 return -EINVAL;
2926 }
2927
readHotplugStatus()2928 bool ExynosDisplayDrmInterface::readHotplugStatus() {
2929 if (mDrmConnector == nullptr) {
2930 return false;
2931 }
2932
2933 uint32_t numConfigs = 0;
2934 int32_t err = getDisplayConfigs(&numConfigs, NULL);
2935
2936 return (err == HWC2_ERROR_NONE && numConfigs > 0 && mExynosDisplay->mPlugState);
2937 }
2938
retrievePanelFullResolution()2939 void ExynosDisplayDrmInterface::retrievePanelFullResolution() {
2940 std::lock_guard<std::recursive_mutex> lock(mDrmConnector->modesLock());
2941
2942 // The largest resolution in the modes of mDrmConnector is the panel full resolution.
2943 for (auto it = mDrmConnector->modes().begin(); it != mDrmConnector->modes().end(); it++) {
2944 if (it->h_display() * it->v_display() >
2945 mPanelFullResolutionHSize * mPanelFullResolutionVSize) {
2946 mPanelFullResolutionHSize = it->h_display();
2947 mPanelFullResolutionVSize = it->v_display();
2948 }
2949 }
2950
2951 if (mPanelFullResolutionHSize <= 0 || mPanelFullResolutionVSize <= 0) {
2952 ALOGE("%s: failed to get panel full resolution", __func__);
2953 } else {
2954 ALOGI("%s: panel full resolution: (%dx%d)", __func__, mPanelFullResolutionHSize,
2955 mPanelFullResolutionVSize);
2956 }
2957 }
2958
setHistogramChannelConfigBlob(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,uint8_t channelId,uint32_t blobId)2959 int32_t ExynosDisplayDrmInterface::setHistogramChannelConfigBlob(
2960 ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq, uint8_t channelId, uint32_t blobId) {
2961 int ret = NO_ERROR;
2962
2963 ATRACE_NAME(String8::format("%s(chan#%u,blob#%u)", __func__, channelId, blobId).c_str());
2964
2965 const DrmProperty& prop = mDrmCrtc->histogram_channel_property(channelId);
2966 if (!prop.id()) {
2967 ALOGE("%s: Unsupported multi-channel histrogram for chan#%d", __func__, channelId);
2968 return -ENOTSUP;
2969 }
2970
2971 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
2972 HWC_LOGE(mExynosDisplay, "%s: Failed to add property for chan#%d and blob#%d, ret(%d)",
2973 __func__, channelId, blobId, ret);
2974 return ret;
2975 }
2976
2977 return ret;
2978 }
2979
clearHistogramChannelConfigBlob(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,uint8_t channelId)2980 int32_t ExynosDisplayDrmInterface::clearHistogramChannelConfigBlob(
2981 ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq, uint8_t channelId) {
2982 int ret = NO_ERROR;
2983
2984 ATRACE_NAME(String8::format("%s(chan#%u)", __func__, channelId).c_str());
2985
2986 const DrmProperty& prop = mDrmCrtc->histogram_channel_property(channelId);
2987 if (!prop.id()) {
2988 ALOGE("%s: Unsupported multi-channel histrogram for chan#%d", __func__, channelId);
2989 return -ENOTSUP;
2990 }
2991
2992 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, 0)) < 0) {
2993 HWC_LOGE(mExynosDisplay, "%s: Failed to add property for chan#%d and blob#0, ret(%d)",
2994 __func__, channelId, ret);
2995 return ret;
2996 }
2997
2998 return ret;
2999 }
3000
3001 // TODO: b/295990513 - Remove the if defined after kernel prebuilts are merged.
3002 #if defined(EXYNOS_HISTOGRAM_CHANNEL_REQUEST)
sendHistogramChannelIoctl(HistogramChannelIoctl_t control,uint32_t chanId) const3003 int32_t ExynosDisplayDrmInterface::sendHistogramChannelIoctl(HistogramChannelIoctl_t control,
3004 uint32_t chanId) const {
3005 struct exynos_drm_histogram_channel_request histogramRequest;
3006
3007 histogramRequest.crtc_id = mDrmCrtc->id();
3008 histogramRequest.hist_id = chanId;
3009
3010 if (control == HistogramChannelIoctl_t::REQUEST) {
3011 ATRACE_NAME(String8::format("requestIoctl(chan#%u)", chanId).c_str());
3012 return mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_CHANNEL_REQUEST,
3013 (void*)&histogramRequest);
3014 } else if (control == HistogramChannelIoctl_t::CANCEL) {
3015 ATRACE_NAME(String8::format("cancelIoctl(chan#%u)", chanId).c_str());
3016 return mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_CHANNEL_CANCEL,
3017 (void*)&histogramRequest);
3018 } else {
3019 ALOGE("%s: unknown control %d", __func__, (int)control);
3020 return BAD_VALUE;
3021 }
3022 }
3023 #else
sendHistogramChannelIoctl(HistogramChannelIoctl_t control,uint32_t blobId) const3024 int32_t ExynosDisplayDrmInterface::sendHistogramChannelIoctl(HistogramChannelIoctl_t control,
3025 uint32_t blobId) const {
3026 ALOGE("%s: kernel doesn't support multi channel histogram ioctl", __func__);
3027 return INVALID_OPERATION;
3028 }
3029 #endif
3030
3031 #if defined(EXYNOS_CONTEXT_HISTOGRAM_EVENT_REQUEST)
sendContextHistogramIoctl(ContextHistogramIoctl_t control,uint32_t blobId) const3032 int32_t ExynosDisplayDrmInterface::sendContextHistogramIoctl(ContextHistogramIoctl_t control,
3033 uint32_t blobId) const {
3034 struct exynos_drm_context_histogram_arg histogramRequest;
3035
3036 histogramRequest.crtc_id = mDrmCrtc->id();
3037 histogramRequest.user_handle = blobId;
3038 histogramRequest.flags = 0;
3039
3040 if (control == ContextHistogramIoctl_t::REQUEST) {
3041 ATRACE_NAME(String8::format("requestIoctl(blob#%u)", blobId).c_str());
3042 return mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_CONTEXT_HISTOGRAM_EVENT_REQUEST,
3043 (void*)&histogramRequest);
3044 } else if (control == ContextHistogramIoctl_t::CANCEL) {
3045 ATRACE_NAME(String8::format("cancelIoctl(blob#%u)", blobId).c_str());
3046 return mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_CONTEXT_HISTOGRAM_EVENT_CANCEL,
3047 (void*)&histogramRequest);
3048 } else {
3049 ALOGE("%s: unknown control %d", __func__, (int)control);
3050 return BAD_VALUE;
3051 }
3052 }
3053 #else
sendContextHistogramIoctl(ContextHistogramIoctl_t control,uint32_t blobId) const3054 int32_t ExynosDisplayDrmInterface::sendContextHistogramIoctl(ContextHistogramIoctl_t control,
3055 uint32_t blobId) const {
3056 ALOGE("%s: kernel doesn't support context histogram ioctl", __func__);
3057 return INVALID_OPERATION;
3058 }
3059 #endif
3060
3061 static constexpr auto kDpHotplugErrorCodeSysfsPath =
3062 "/sys/devices/platform/110f0000.drmdp/drm-displayport/dp_hotplug_error_code";
3063
readHotplugErrorCode()3064 int ExynosDisplayDrmInterface::readHotplugErrorCode() {
3065 if (mExynosDisplay->mType != HWC_DISPLAY_EXTERNAL) return 0;
3066 int hotplug_error_code = 0;
3067 std::ifstream ifs(kDpHotplugErrorCodeSysfsPath);
3068 if (ifs.is_open()) ifs >> hotplug_error_code;
3069 return hotplug_error_code;
3070 }
3071
resetHotplugErrorCode()3072 void ExynosDisplayDrmInterface::resetHotplugErrorCode() {
3073 if (mExynosDisplay->mType != HWC_DISPLAY_EXTERNAL) return;
3074 std::ofstream ofs(kDpHotplugErrorCodeSysfsPath);
3075 if (ofs.is_open()) ofs << "0";
3076 }
3077
handleDrmPropertyUpdate(uint32_t connector_id,uint32_t prop_id)3078 void ExynosDisplayDrmInterface::handleDrmPropertyUpdate(uint32_t connector_id, uint32_t prop_id) {
3079 if (!mDrmConnector || mDrmConnector->id() != connector_id) return;
3080 auto& conn_props = mDrmConnector->properties();
3081 auto prop = std::find_if(conn_props.begin(), conn_props.end(),
3082 [prop_id](const DrmProperty* prop) { return prop->id() == prop_id; });
3083 if (prop == conn_props.end()) {
3084 ALOGD("%s: Unknown property prop_id=%u", __func__, prop_id);
3085 return;
3086 }
3087 mDrmDevice->UpdateConnectorProperty(*mDrmConnector, *prop);
3088 if ((*prop)->id() == mDrmConnector->content_protection().id()) {
3089 auto [ret, content_protection_value] = mDrmConnector->content_protection().value();
3090 if (ret < 0) {
3091 ALOGW("%s: failed to get DRM content_protection property value ret=%d", __func__, ret);
3092 return;
3093 }
3094 bool protectionEnabled = (content_protection_value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
3095 HdcpLevels hdcpLevels;
3096 hdcpLevels.connectedLevel = protectionEnabled ? HdcpLevel::HDCP_V1 : HdcpLevel::HDCP_NONE;
3097 hdcpLevels.maxLevel = HdcpLevel::HDCP_V1;
3098 mExynosDisplay->contentProtectionUpdated(hdcpLevels);
3099 }
3100 }
3101
setManufacturerInfo(uint8_t edid8,uint8_t edid9)3102 void ExynosDisplayDrmInterface::setManufacturerInfo(uint8_t edid8, uint8_t edid9) {
3103 mManufacturerInfo = edid9 << 8 | edid8;
3104 }
3105
setProductId(uint8_t edid10,uint8_t edid11)3106 void ExynosDisplayDrmInterface::setProductId(uint8_t edid10, uint8_t edid11) {
3107 mProductId = edid11 << 8 | edid10;
3108 }
3109
borrowedCrtcFrom()3110 ExynosDisplay* ExynosDisplayDrmInterface::borrowedCrtcFrom() {
3111 return mBorrowedCrtcFrom;
3112 }
3113
swapCrtcs(ExynosDisplay * anotherDisplay)3114 int32_t ExynosDisplayDrmInterface::swapCrtcs(ExynosDisplay* anotherDisplay) {
3115 if (!anotherDisplay) {
3116 HWC_LOGE(mExynosDisplay, "%s: failed, anotherDisplay is null", __func__);
3117 return -EINVAL;
3118 }
3119 ExynosDisplayDrmInterface* anotherDisplayIntf =
3120 static_cast<ExynosDisplayDrmInterface*>(anotherDisplay->mDisplayInterface.get());
3121 if (!anotherDisplayIntf) {
3122 HWC_LOGE(mExynosDisplay, "%s: failed to get ExynosDisplayDrmInterface of display %s",
3123 __func__, anotherDisplay->mDisplayTraceName.c_str());
3124 return -EINVAL;
3125 }
3126
3127 if (borrowedCrtcFrom() != nullptr && borrowedCrtcFrom() != anotherDisplay) {
3128 HWC_LOGE(mExynosDisplay, "%s: display %s is already using decon borrowed from %s", __func__,
3129 mExynosDisplay->mDisplayTraceName.c_str(),
3130 borrowedCrtcFrom()->mDisplayTraceName.c_str());
3131 return -EINVAL;
3132 }
3133
3134 if (!mDrmCrtc || !mDrmConnector) {
3135 HWC_LOGE(mExynosDisplay, "%s: failed to get crtc or connector of display %s", __func__,
3136 mExynosDisplay->mDisplayTraceName.c_str());
3137 return -EINVAL;
3138 }
3139
3140 DrmCrtc* anotherCrtc = anotherDisplayIntf->mDrmCrtc;
3141 DrmConnector* anotherConnector = anotherDisplayIntf->mDrmConnector;
3142 if (!anotherCrtc || !anotherConnector) {
3143 HWC_LOGE(mExynosDisplay, "%s: failed to get crtc or connector of display %s", __func__,
3144 anotherDisplay->mDisplayTraceName.c_str());
3145 return -EINVAL;
3146 }
3147
3148 ALOGD("%s: switching %s (curr decon %u) <-> %s (curr decon %u)", __func__,
3149 mExynosDisplay->mDisplayTraceName.c_str(), mDrmCrtc->pipe(),
3150 anotherDisplay->mDisplayTraceName.c_str(), anotherCrtc->pipe());
3151
3152 anotherDisplayIntf->clearDisplay(true);
3153
3154 mDrmCrtc->set_display(anotherConnector->display());
3155 anotherCrtc->set_display(mDrmConnector->display());
3156
3157 mDrmConnector->encoder()->set_crtc(anotherCrtc, anotherConnector->display());
3158 anotherConnector->encoder()->set_crtc(mDrmCrtc, mDrmConnector->display());
3159
3160 int anotherConnDispl = anotherConnector->display();
3161 anotherConnector->set_display(mDrmConnector->display());
3162 mDrmConnector->set_display(anotherConnDispl);
3163
3164 anotherDisplayIntf->mDrmCrtc = mDrmCrtc;
3165 mDrmCrtc = anotherCrtc;
3166
3167 clearOldCrtcBlobs();
3168 anotherDisplayIntf->clearOldCrtcBlobs();
3169
3170 if (mBorrowedCrtcFrom == anotherDisplay) {
3171 mBorrowedCrtcFrom = nullptr;
3172 } else {
3173 mBorrowedCrtcFrom = anotherDisplay;
3174 }
3175 return 0;
3176 }
3177