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 #ifndef _EXYNOSDISPLAYDRMINTERFACE_H
18 #define _EXYNOSDISPLAYDRMINTERFACE_H
19 
20 #include <drm/samsung_drm.h>
21 #include <utils/Condition.h>
22 #include <utils/Mutex.h>
23 #include <xf86drmMode.h>
24 
25 #include <list>
26 #include <unordered_map>
27 
28 #include "ExynosDisplay.h"
29 #include "ExynosDisplayInterface.h"
30 #include "ExynosHWC.h"
31 #include "ExynosMPP.h"
32 #include "drmconnector.h"
33 #include "drmcrtc.h"
34 #include "vsyncworker.h"
35 
36 /* Max plane number of buffer object */
37 #define HWC_DRM_BO_MAX_PLANES 4
38 
39 #ifndef HWC_FORCE_PANIC_PATH
40 #define HWC_FORCE_PANIC_PATH "/d/dpu/panic"
41 #endif
42 
43 using namespace android;
44 using DrmPropertyMap = std::unordered_map<uint32_t, uint64_t>;
45 
46 class ExynosDevice;
47 
48 using BufHandles = std::array<uint32_t, HWC_DRM_BO_MAX_PLANES>;
49 class FramebufferManager {
50     public:
FramebufferManager()51         FramebufferManager(){};
52         ~FramebufferManager();
53         void init(int drmFd);
54 
55         // get buffer for provided config, if a buffer with same config is already cached it will be
56         // reused otherwise one will be allocated. returns fbId that can be used to attach to the
57         // plane, any buffers allocated/reused with this call will be bound to the corresponding
58         // layer. Those fbIds will be cleaned up once the layer was destroyed.
59         int32_t getBuffer(const exynos_win_config_data &config, uint32_t &fbId);
60 
61         bool checkShrink();
62 
63         void cleanup(const ExynosLayer *layer);
64 
65         // The flip function is to help clean up the cached fbIds of destroyed
66         // layers after the previous fdIds were update successfully on the
67         // screen.
68         // This should be called after the frame update.
69         void flip(bool hasSecureFrameBuffer);
70 
71         // release all currently tracked buffers, this can be called for example when display is turned
72         // off
73         void releaseAll();
74 
75     private:
76         // this struct should contain elements that can be used to identify framebuffer more easily
77         struct Framebuffer {
78             struct BufferDesc {
79                 uint64_t bufferId;
80                 int drmFormat;
81                 bool isSecure;
82                 bool operator==(const Framebuffer::BufferDesc &rhs) const {
83                     return (bufferId == rhs.bufferId && drmFormat == rhs.drmFormat &&
84                             isSecure == rhs.isSecure);
85                 }
86             };
87             struct SolidColorDesc {
88                 uint32_t width;
89                 uint32_t height;
90                 bool operator==(const Framebuffer::SolidColorDesc &rhs) const {
91                     return (width == rhs.width && height == rhs.height);
92                 }
93             };
94 
FramebufferFramebuffer95             explicit Framebuffer(int fd, uint32_t fb, BufferDesc desc)
96                   : drmFd(fd), fbId(fb), bufferDesc(desc){};
FramebufferFramebuffer97             explicit Framebuffer(int fd, uint32_t fb, SolidColorDesc desc)
98                   : drmFd(fd), fbId(fb), colorDesc(desc){};
~FramebufferFramebuffer99             ~Framebuffer() { drmModeRmFB(drmFd, fbId); };
100             int drmFd;
101             uint32_t fbId;
102             union {
103                 BufferDesc bufferDesc;
104                 SolidColorDesc colorDesc;
105             };
106         };
107         using FBList = std::list<std::unique_ptr<Framebuffer>>;
108 
109         template <class UnaryPredicate>
110         uint32_t findCachedFbId(const ExynosLayer *layer, UnaryPredicate predicate);
111         int addFB2WithModifiers(uint32_t width, uint32_t height, uint32_t pixel_format,
112                         const BufHandles handles, const uint32_t pitches[4],
113                         const uint32_t offsets[4], const uint64_t modifier[4], uint32_t *buf_id,
114                         uint32_t flags);
115         uint32_t getBufHandleFromFd(int fd);
116         void freeBufHandle(uint32_t handle);
117         void removeFBsThreadRoutine();
118 
119         void markInuseLayerLocked(const ExynosLayer *layer) REQUIRES(mMutex);
120         void destroyUnusedLayersLocked() REQUIRES(mMutex);
121         void destroySecureFramebufferLocked() REQUIRES(mMutex);
122 
123         int mDrmFd = -1;
124 
125         // mCachedLayerBuffers map keep the relationship between Layer and
126         // FBList. The map entry will be deleted once the layer is destroyed.
127         std::map<const ExynosLayer *, FBList> mCachedLayerBuffers;
128 
129         // mCleanBuffers list keeps fbIds of destroyed layers. Those fbIds will
130         // be destroyed in mRmFBThread thread.
131         FBList mCleanBuffers;
132 
133         // mCacheShrinkPending is set when we want to clean up unused layers
134         // in mCachedLayerBuffers. When the flag is set, mCachedLayersInuse will
135         // keep in-use layers in this frame update. Those unused layers will be
136         // freed at the end of the update.
137         // TODO: have a better way to maintain inuse layers
138         bool mCacheShrinkPending = false;
139         bool mHasSecureFramebuffer = false;
140         std::set<const ExynosLayer *> mCachedLayersInuse;
141 
142         std::thread mRmFBThread;
143         bool mRmFBThreadRunning = false;
144         Condition mFlipDone;
145         Mutex mMutex;
146 
147         static constexpr size_t MAX_CACHED_LAYERS = 16;
148         static constexpr size_t MAX_CACHED_BUFFERS_PER_LAYER = 32;
149 };
150 
isFramebuffer(const ExynosLayer * layer)151 inline bool isFramebuffer(const ExynosLayer *layer) {
152     return layer == nullptr;
153 }
154 
155 template <class UnaryPredicate>
findCachedFbId(const ExynosLayer * layer,UnaryPredicate predicate)156 uint32_t FramebufferManager::findCachedFbId(const ExynosLayer *layer, UnaryPredicate predicate) {
157     Mutex::Autolock lock(mMutex);
158     markInuseLayerLocked(layer);
159     const auto &cachedBuffers = mCachedLayerBuffers[layer];
160     const auto it = std::find_if(cachedBuffers.begin(), cachedBuffers.end(), predicate);
161     return (it != cachedBuffers.end()) ? (*it)->fbId : 0;
162 }
163 
164 class ExynosDisplayDrmInterface :
165     public ExynosDisplayInterface,
166     public VsyncCallback
167 {
168     public:
169         class DrmModeAtomicReq {
170             public:
171                 DrmModeAtomicReq(ExynosDisplayDrmInterface *displayInterface);
172                 ~DrmModeAtomicReq();
173 
174                 DrmModeAtomicReq(const DrmModeAtomicReq&) = delete;
175                 DrmModeAtomicReq& operator=(const DrmModeAtomicReq&) = delete;
176 
pset()177                 drmModeAtomicReqPtr pset() { return mPset; };
savePset()178                 void savePset() {
179                     if (mSavedPset) {
180                         drmModeAtomicFree(mSavedPset);
181                     }
182                     mSavedPset = drmModeAtomicDuplicate(mPset);
183                 }
restorePset()184                 void restorePset() {
185                     if (mPset) {
186                         drmModeAtomicFree(mPset);
187                     }
188                     mPset = mSavedPset;
189                     mSavedPset = NULL;
190                 }
191 
setError(int err)192                 void setError(int err) { mError = err; };
getError()193                 int getError() { return mError; };
194                 int32_t atomicAddProperty(const uint32_t id,
195                         const DrmProperty &property,
196                         uint64_t value, bool optional = false);
197                 String8& dumpAtomicCommitInfo(String8 &result, bool debugPrint = false);
198                 int commit(uint32_t flags, bool loggingForDebug = false);
addOldBlob(uint32_t blob_id)199                 void addOldBlob(uint32_t blob_id) {
200                     mOldBlobs.push_back(blob_id);
201                 };
destroyOldBlobs()202                 int destroyOldBlobs() {
203                     for (auto &blob : mOldBlobs) {
204                         int ret = mDrmDisplayInterface->mDrmDevice->DestroyPropertyBlob(blob);
205                         if (ret) {
206                             HWC_LOGE(mDrmDisplayInterface->mExynosDisplay,
207                                     "Failed to destroy old blob after commit %d", ret);
208                             return ret;
209                         }
210                     }
211                     mOldBlobs.clear();
212                     return NO_ERROR;
213                 };
214             private:
215                 drmModeAtomicReqPtr mPset;
216                 drmModeAtomicReqPtr mSavedPset;
217                 int mError = 0;
218                 ExynosDisplayDrmInterface *mDrmDisplayInterface = NULL;
219                 /* Destroy old blobs after commit */
220                 std::vector<uint32_t> mOldBlobs;
drmFd()221                 int drmFd() const { return mDrmDisplayInterface->mDrmDevice->fd(); }
222         };
223         class ExynosVsyncCallback {
224             public:
enableVSync(bool enable)225                 void enableVSync(bool enable) {
226                     mVsyncEnabled = enable;
227                     resetVsyncTimeStamp();
228                 };
getVSyncEnabled()229                 bool getVSyncEnabled() { return mVsyncEnabled; };
setDesiredVsyncPeriod(uint64_t period)230                 void setDesiredVsyncPeriod(uint64_t period) {
231                     mDesiredVsyncPeriod = period;
232                     resetVsyncTimeStamp();
233                 };
getDesiredVsyncPeriod()234                 uint64_t getDesiredVsyncPeriod() { return mDesiredVsyncPeriod;};
getVsyncTimeStamp()235                 uint64_t getVsyncTimeStamp() { return mVsyncTimeStamp; };
getVsyncPeriod()236                 uint64_t getVsyncPeriod() { return mVsyncPeriod; };
237                 bool Callback(int display, int64_t timestamp);
resetVsyncTimeStamp()238                 void resetVsyncTimeStamp() { mVsyncTimeStamp = 0; };
resetDesiredVsyncPeriod()239                 void resetDesiredVsyncPeriod() { mDesiredVsyncPeriod = 0;};
240             private:
241                 bool mVsyncEnabled = false;
242                 uint64_t mVsyncTimeStamp = 0;
243                 uint64_t mVsyncPeriod = 0;
244                 uint64_t mDesiredVsyncPeriod = 0;
245         };
246         void Callback(int display, int64_t timestamp) override;
247 
248         ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay);
249         ~ExynosDisplayDrmInterface();
250         virtual void init(ExynosDisplay *exynosDisplay);
251         virtual int32_t setPowerMode(int32_t mode);
252         virtual int32_t setLowPowerMode() override;
isDozeModeAvailable()253         virtual bool isDozeModeAvailable() const {
254             return mDozeDrmMode.h_display() > 0 && mDozeDrmMode.v_display() > 0;
255         };
256         virtual int32_t setVsyncEnabled(uint32_t enabled);
257         virtual int32_t getDisplayConfigs(
258                 uint32_t* outNumConfigs,
259                 hwc2_config_t* outConfigs);
260         virtual void dumpDisplayConfigs();
261         virtual bool supportDataspace(int32_t dataspace);
262         virtual int32_t getColorModes(uint32_t* outNumModes, int32_t* outModes);
263         virtual int32_t setColorMode(int32_t mode);
264         virtual int32_t setActiveConfig(hwc2_config_t config);
265         virtual int32_t setCursorPositionAsync(uint32_t x_pos, uint32_t y_pos);
266         virtual int32_t updateHdrCapabilities();
267         virtual int32_t deliverWinConfigData();
268         virtual int32_t clearDisplay(bool needModeClear = false);
269         virtual int32_t disableSelfRefresh(uint32_t disable);
270         virtual int32_t setForcePanic();
getDisplayFd()271         virtual int getDisplayFd() { return mDrmDevice->fd(); };
272         virtual int32_t initDrmDevice(DrmDevice *drmDevice);
273         virtual uint32_t getDrmDisplayId(uint32_t type, uint32_t index);
274         virtual uint32_t getMaxWindowNum();
275         virtual int32_t getReadbackBufferAttributes(int32_t* /*android_pixel_format_t*/ outFormat,
276                 int32_t* /*android_dataspace_t*/ outDataspace);
277         virtual int32_t getDisplayIdentificationData(uint8_t* outPort,
278                 uint32_t* outDataSize, uint8_t* outData);
279 
280         /* For HWC 2.4 APIs */
281         virtual int32_t getDisplayVsyncPeriod(
282                 hwc2_vsync_period_t* outVsyncPeriod);
283         virtual int32_t getConfigChangeDuration();
284         virtual int32_t getVsyncAppliedTime(hwc2_config_t config,
285                 int64_t* actualChangeTime);
286         virtual int32_t setActiveConfigWithConstraints(
287                 hwc2_config_t config, bool test = false);
288 
setDisplayColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)289         virtual int32_t setDisplayColorSetting(
290                 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
291         { return NO_ERROR;};
setPlaneColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const std::unique_ptr<DrmPlane> & plane,const exynos_win_config_data & config)292         virtual int32_t setPlaneColorSetting(
293                 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
294                 const std::unique_ptr<DrmPlane> &plane,
295                 const exynos_win_config_data& config)
296         { return NO_ERROR;};
297         virtual int32_t updateBrightness(bool syncFrame);
298         virtual float getSdrDimRatio();
299         virtual void destroyLayer(ExynosLayer *layer) override;
300 
301         virtual int32_t waitVBlank();
isHbmOn()302         bool isHbmOn() {
303             return mBrightnessCtrl.HbmMode.get() != static_cast<uint32_t>(HbmMode::OFF);
304         }
getDbv()305         uint32_t getDbv() { return mBrightnessLevel.get(); }
getDesiredRefreshRate()306         float getDesiredRefreshRate() { return mDesiredModeState.mode.v_refresh(); }
307     protected:
308         struct ModeState {
309             bool needs_modeset = false;
310             DrmMode mode;
311             uint32_t blob_id = 0;
312             uint32_t old_blob_id = 0;
setModeModeState313             void setMode(const DrmMode newMode, const uint32_t modeBlob,
314                     DrmModeAtomicReq &drmReq) {
315                 drmReq.addOldBlob(old_blob_id);
316                 mode = newMode;
317                 old_blob_id = blob_id;
318                 blob_id = modeBlob;
319             };
resetModeState320             void reset() {
321                 *this = {};
322             };
applyModeState323             void apply(ModeState &toModeState, DrmModeAtomicReq &drmReq) {
324                 toModeState.setMode(mode, blob_id, drmReq);
325                 drmReq.addOldBlob(old_blob_id);
326                 reset();
327             };
328         };
329         int32_t createModeBlob(const DrmMode &mode, uint32_t &modeBlob);
330         int32_t setDisplayMode(DrmModeAtomicReq &drmReq, const uint32_t modeBlob);
331         int32_t clearDisplayMode(DrmModeAtomicReq &drmReq);
332         int32_t chosePreferredConfig();
333         int getDeconChannel(ExynosMPP *otfMPP);
334         static std::tuple<uint64_t, int> halToDrmEnum(
335                 const int32_t halData, const DrmPropertyMap &drmEnums);
336         /*
337          * This function adds FB and gets new fb id if fbId is 0,
338          * if fbId is not 0, this reuses fbId.
339          */
340         int32_t setupCommitFromDisplayConfig(DrmModeAtomicReq &drmReq,
341                 const exynos_win_config_data &config,
342                 const uint32_t configIndex,
343                 const std::unique_ptr<DrmPlane> &plane,
344                 uint32_t &fbId);
345 
346         int32_t setupPartialRegion(DrmModeAtomicReq &drmReq);
347         static void parseEnums(const DrmProperty &property,
348                 const std::vector<std::pair<uint32_t, const char *>> &enums,
349                 DrmPropertyMap &out_enums);
350         void parseBlendEnums(const DrmProperty &property);
351         void parseStandardEnums(const DrmProperty &property);
352         void parseTransferEnums(const DrmProperty &property);
353         void parseRangeEnums(const DrmProperty &property);
354         void parseColorModeEnums(const DrmProperty &property);
355 
356         int32_t setupWritebackCommit(DrmModeAtomicReq &drmReq);
357         int32_t clearWritebackCommit(DrmModeAtomicReq &drmReq);
358 
359     private:
360         int32_t updateColorSettings(DrmModeAtomicReq &drmReq, uint64_t dqeEnabled);
361         int32_t getLowPowerDrmModeModeInfo();
362         int32_t setActiveDrmMode(DrmMode const &mode);
363 
364     protected:
365         struct PartialRegionState {
366             struct drm_clip_rect partial_rect = {0, 0, 0, 0};
367             uint32_t blob_id = 0;
isUpdatedPartialRegionState368             bool isUpdated(drm_clip_rect rect) {
369                 return ((partial_rect.x1 != rect.x1) ||
370                         (partial_rect.y1 != rect.y1) ||
371                         (partial_rect.x2 != rect.x2) ||
372                         (partial_rect.y2 != rect.y2));
373             };
374         };
375 
376         class DrmReadbackInfo {
377             public:
378                 void init(DrmDevice *drmDevice, uint32_t displayId);
~DrmReadbackInfo()379                 ~DrmReadbackInfo() {
380                     if (mDrmDevice == NULL)
381                         return;
382                     if (mOldFbId > 0)
383                         drmModeRmFB(mDrmDevice->fd(), mOldFbId);
384                     if (mFbId > 0)
385                         drmModeRmFB(mDrmDevice->fd(), mFbId);
386                 }
getWritebackConnector()387                 DrmConnector* getWritebackConnector() { return mWritebackConnector; };
setFbId(uint32_t fbId)388                 void setFbId(uint32_t fbId) {
389                     if ((mDrmDevice != NULL) && (mOldFbId > 0))
390                         drmModeRmFB(mDrmDevice->fd(), mOldFbId);
391                     mOldFbId = mFbId;
392                     mFbId = fbId;
393                 }
394                 void pickFormatDataspace();
395                 static constexpr uint32_t PREFERRED_READBACK_FORMAT =
396                     HAL_PIXEL_FORMAT_RGBA_8888;
397                 uint32_t mReadbackFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
398                 bool mNeedClearReadbackCommit = false;
399             private:
400                 DrmDevice *mDrmDevice = NULL;
401                 DrmConnector *mWritebackConnector = NULL;
402                 uint32_t mFbId = 0;
403                 uint32_t mOldFbId = 0;
404                 std::vector<uint32_t> mSupportedFormats;
405         };
406         DrmDevice *mDrmDevice;
407         DrmCrtc *mDrmCrtc;
408         DrmConnector *mDrmConnector;
409         VSyncWorker mDrmVSyncWorker;
410         ExynosVsyncCallback mVsyncCallback;
411         ModeState mActiveModeState;
412         ModeState mDesiredModeState;
413         PartialRegionState mPartialRegionState;
414         /* Mapping plane id to ExynosMPP, key is plane id */
415         std::unordered_map<uint32_t, ExynosMPP*> mExynosMPPsForPlane;
416 
417         DrmPropertyMap mBlendEnums;
418         DrmPropertyMap mStandardEnums;
419         DrmPropertyMap mTransferEnums;
420         DrmPropertyMap mRangeEnums;
421         DrmPropertyMap mColorModeEnums;
422 
423         DrmReadbackInfo mReadbackInfo;
424 
425     private:
426         DrmMode mDozeDrmMode;
427 
428     protected:
429         void getBrightnessInterfaceSupport();
430         void setupBrightnessConfig();
431         void parseHbmModeEnums(const DrmProperty &property);
432         void checkHbmSvDimming();
433         void endHbmSvDimming();
434         FILE *mHbmModeFd;
435         FILE *mDimmingOnFd;
436         bool mBrightntessIntfSupported = false;
437         float mBrightnessHbmMax = 1.0f;
438         enum class PanelHbmType {
439             ONE_STEP,
440             CONTINUOUS,
441         };
442         enum BrightnessRange {
443             NORMAL = 0,
444             HBM,
445             MAX,
446         };
447         enum class HbmMode {
448             OFF = 0,
449             ON_IRC_ON,
450             ON_IRC_OFF,
451         };
452 
453         DrmPropertyMap mHbmModeEnums;
454         PanelHbmType mPanelHbmType;
455 
456         Mutex mBrightnessUpdateMutex;
457         brightnessState_t mBrightnessState;
458         CtrlValue<uint32_t> mBrightnessLevel;
459         float mScaledBrightness;
460         typedef struct brightnessCtrl {
461             CtrlValue<bool> DimmingOn;
462             CtrlValue<uint32_t> HbmMode;
463             CtrlValue<bool> LhbmOn;
resetbrightnessCtrl464             void reset() {
465                 DimmingOn.store(false);
466                 DimmingOn.clear_dirty();
467                 HbmMode.store(0);
468                 HbmMode.clear_dirty();
469                 LhbmOn.store(false);
470                 LhbmOn.clear_dirty();
471             }
472         } brightnessCtrl_t;
473         brightnessCtrl_t mBrightnessCtrl;
474 
475         struct BrightnessTable {
476             float mBriStart;
477             float mBriEnd;
478             uint32_t mBklStart;
479             uint32_t mBklEnd;
480             uint32_t mNitsStart;
481             uint32_t mNitsEnd;
BrightnessTableBrightnessTable482             BrightnessTable() {}
BrightnessTableBrightnessTable483             BrightnessTable(const brightness_attribute &attr)
484                   : mBriStart(static_cast<float>(attr.percentage.min) / 100.0f),
485                     mBriEnd(static_cast<float>(attr.percentage.max) / 100.0f),
486                     mBklStart(attr.level.min),
487                     mBklEnd(attr.level.max),
488                     mNitsStart(attr.nits.min),
489                     mNitsEnd(attr.nits.max) {}
490         };
491         struct BrightnessTable mBrightnessTable[BrightnessRange::MAX];
492 
493         // TODO: hbm in dual display is not supported. It should support it in
494         //      the furture.
495         static constexpr const char *kHbmModeFileNode =
496                 "/sys/class/backlight/panel%d-backlight/hbm_mode";
497         static constexpr const char *kDimmingOnFileNode =
498                 "/sys/class/backlight/panel%d-backlight/dimming_on";
499 
500         static constexpr int32_t kHbmDimmingTimeUs = 5000000;
501 
502         FramebufferManager mFBManager;
503 
504         /*
505          * BrightnessDimmingUsage:
506          * NORMAL- enable dimming
507          * HBM-    enable dimming only for hbm transition
508          * NONE-   disable dimming
509          */
510         enum class BrightnessDimmingUsage {
511             NORMAL = 0,
512             HBM,
513             NONE,
514         };
515 
516         BrightnessDimmingUsage mBrightnessDimmingUsage;
517         bool mHbmSvDimming;
518         int32_t mHbmDimmingTimeUs;
519         std::thread mDimmingThread;
520         bool mHbmSvDimmingThreadRunning;
521         Condition mHbmSvDimmingCond;
522         Mutex mHbmSvDimmingMutex;
523 
524     private:
525         int32_t getDisplayFakeEdid(uint8_t &outPort, uint32_t &outDataSize, uint8_t *outData);
526 };
527 
528 #endif
529