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