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