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