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