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