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