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