1 /*
2  * Copyright (C) 2012 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 #include "ExynosExternalDisplay.h"
18 #include <errno.h>
19 #include <hardware/hwcomposer_defs.h>
20 #include <linux/fb.h>
21 #include "ExynosDevice.h"
22 #include "ExynosDisplayDrmInterface.h"
23 #include "ExynosDisplayDrmInterfaceModule.h"
24 #include "ExynosHWCDebug.h"
25 #include "ExynosHWCHelper.h"
26 #include "ExynosLayer.h"
27 #include "pixelstats-display.h"
28 
29 #define SKIP_FRAME_COUNT 3
30 extern struct exynos_hwc_control exynosHWCControl;
31 
32 using namespace SOC_VERSION;
33 
ExynosExternalDisplay(uint32_t index,ExynosDevice * device,const std::string & displayName)34 ExynosExternalDisplay::ExynosExternalDisplay(uint32_t index, ExynosDevice* device,
35                                              const std::string& displayName)
36       : ExynosDisplay(HWC_DISPLAY_EXTERNAL, index, device, displayName) {
37     DISPLAY_LOGD(eDebugExternalDisplay, "");
38 
39     mEnabled = false;
40     mBlanked = false;
41 
42 	mXres = 0;
43     mYres = 0;
44     mXdpi = 0;
45     mYdpi = 0;
46     mVsyncPeriod = 0;
47     mSkipStartFrame = 0;
48     mSkipFrameCount = -1;
49     mIsSkipFrame = false;
50     mVirtualDisplayState = 0;
51 
52     mDRDefault = true;
53     mDREnable = false;
54 
55     //TODO : Hard coded currently
56     mNumMaxPriorityAllowed = 1;
57     mPowerModeState = (hwc2_power_mode_t)HWC_POWER_MODE_OFF;
58     mDisplayControl.multiThreadedPresent = true;
59 }
60 
~ExynosExternalDisplay()61 ExynosExternalDisplay::~ExynosExternalDisplay()
62 {
63 
64 }
65 
init()66 void ExynosExternalDisplay::init()
67 {
68 
69 }
70 
deInit()71 void ExynosExternalDisplay::deInit()
72 {
73 
74 }
75 
openExternalDisplay()76 int ExynosExternalDisplay::openExternalDisplay()
77 {
78     DISPLAY_LOGD(eDebugExternalDisplay, "");
79 
80     int ret = 0;
81 
82     mSkipFrameCount = SKIP_FRAME_COUNT;
83     mSkipStartFrame = 0;
84     mPlugState = true;
85     setGeometryChanged(GEOMETRY_DEVICE_DISPLAY_ADDED);
86 
87     if (mLayers.size() != 0) {
88         mLayers.clear();
89     }
90 
91     DISPLAY_LOGD(eDebugExternalDisplay, "open fd for External Display(%d)", ret);
92 
93     return ret;
94 }
95 
closeExternalDisplay()96 void ExynosExternalDisplay::closeExternalDisplay()
97 {
98     DISPLAY_LOGD(eDebugExternalDisplay, "");
99 
100     setVsyncEnabledInternal(HWC2_VSYNC_DISABLE);
101 
102     if (mPowerModeState.has_value() &&
103         (*mPowerModeState != (hwc2_power_mode_t)HWC_POWER_MODE_OFF)) {
104         if (mDisplayInterface->setPowerMode(HWC_POWER_MODE_OFF) < 0) {
105             DISPLAY_LOGE("%s: set powermode ioctl failed errno : %d", __func__, errno);
106             return;
107         }
108     }
109 
110     mPowerModeState = (hwc2_power_mode_t)HWC_POWER_MODE_OFF;
111 
112     DISPLAY_LOGD(eDebugExternalDisplay, "Close fd for External Display");
113 
114     mPlugState = false;
115     setGeometryChanged(GEOMETRY_DEVICE_DISPLAY_REMOVED);
116     mEnabled = false;
117     mBlanked = false;
118     mSkipFrameCount = SKIP_FRAME_COUNT;
119 
120     for (size_t i = 0; i < mLayers.size(); i++) {
121         ExynosLayer *layer = mLayers[i];
122         layer->mAcquireFence = fence_close(layer->mAcquireFence, this, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_LAYER);
123         layer->mReleaseFence = -1;
124         layer->mLayerBuffer = NULL;
125     }
126 
127     mClientCompositionInfo.initializeInfosComplete(this);
128     mExynosCompositionInfo.initializeInfosComplete(this);
129 }
130 
getDisplayConfigs(uint32_t * outNumConfigs,hwc2_config_t * outConfigs)131 int ExynosExternalDisplay::getDisplayConfigs(uint32_t* outNumConfigs, hwc2_config_t* outConfigs)
132 {
133     DISPLAY_LOGD(eDebugExternalDisplay, "");
134 
135     int32_t ret = mDisplayInterface->getDisplayConfigs(outNumConfigs, outConfigs);
136     if (ret)
137         DISPLAY_LOGE("%s: failed to getDisplayConfigs, ret(%d)", __func__, ret);
138 
139     if (outConfigs) {
140         char modeStr[PROPERTY_VALUE_MAX] = "\0";
141         int32_t width, height, fps, config;
142         int32_t err = HWC2_ERROR_BAD_CONFIG;
143 
144         if (property_get("vendor.display.external.preferred_mode", modeStr, "") > 0) {
145             if (sscanf(modeStr, "%dx%d@%d", &width, &height, &fps) == 3) {
146                 err = lookupDisplayConfigs(width, height, fps, fps, &config);
147                 if (err != HWC2_ERROR_NONE) {
148                     DISPLAY_LOGW("%s: display does not support preferred mode %dx%d@%d",
149                                  __func__, width, height, fps);
150                 }
151             } else {
152                 DISPLAY_LOGW("%s: vendor.display.external.preferred_mode: bad format",
153                              __func__);
154             }
155         }
156 
157         if (err == HWC2_ERROR_NONE) {
158             mActiveConfig = config;
159         } else {
160             err = lookupDisplayConfigsRelaxed(1920, 1080, 60, &config);
161             if (err == HWC2_ERROR_NONE) {
162                 mActiveConfig = config;
163             } else {
164                 mActiveConfig = outConfigs[0];
165             }
166         }
167 
168         displayConfigs_t displayConfig = mDisplayConfigs[mActiveConfig];
169         mXres = displayConfig.width;
170         mYres = displayConfig.height;
171         mVsyncPeriod = displayConfig.vsyncPeriod;
172         mRefreshRate = displayConfig.refreshRate;
173 
174         if (mDisplayInterface->mType == INTERFACE_TYPE_DRM) {
175             ret = mDisplayInterface->setActiveConfig(mActiveConfig);
176             if (ret) {
177                 DISPLAY_LOGE("%s: failed to setActiveConfigs, ret(%d)", __func__, ret);
178                 return ret;
179             }
180         }
181     }
182 
183     return ret;
184 }
185 
getActiveConfig(hwc2_config_t * outConfig)186 int32_t ExynosExternalDisplay::getActiveConfig(hwc2_config_t* outConfig) {
187     DISPLAY_LOGD(eDebugExternalDisplay, "");
188 
189     if (!mHpdStatus)
190         return HWC2_ERROR_BAD_DISPLAY;
191 
192     if (mActiveConfig == UINT_MAX)
193         return HWC2_ERROR_BAD_CONFIG;
194 
195     *outConfig = mActiveConfig;
196 
197     return HWC2_ERROR_NONE;
198 }
199 
handleRotate()200 bool ExynosExternalDisplay::handleRotate()
201 {
202     // FIXME: HWC2_COMPOSITION_SCREENSHOT is not dfeind in AOSP
203     //        HWC guys should fix this.
204     if (mSkipStartFrame < SKIP_EXTERNAL_FRAME) {
205 #if 0
206         for (size_t i = 0; i < mLayers.size(); i++) {
207             ExynosLayer *layer = mLayers[i];
208             if (layer->mCompositionType == HWC2_COMPOSITION_SCREENSHOT)
209                 layer->mCompositionType = HWC2_COMPOSITION_DEVICE;
210         }
211 #endif
212         mIsSkipFrame = false;
213         return false;
214     }
215 
216 #if 0
217     for (size_t i = 0; i < mLayers.size(); i++) {
218         ExynosLayer *layer = mLayers[i];
219         if (layer->mCompositionType == HWC2_COMPOSITION_SCREENSHOT) {
220             DISPLAY_LOGD(eDebugExternalDisplay, "include rotation animation layer");
221             layer->mOverlayInfo = eSkipRotateAnim;
222             for (size_t j = 0; j < mLayers.size(); j++) {
223                 ExynosLayer *skipLayer = mLayers[j];
224                 skipLayer->updateValidateCompositionType(HWC2_COMPOSITION_DEVICE);
225             }
226             mIsSkipFrame = true;
227             return true;
228         }
229     }
230 #endif
231     mIsSkipFrame = false;
232     return false;
233 }
234 
checkRotate()235 bool ExynosExternalDisplay::checkRotate()
236 {
237     // FIXME: HWC2_COMPOSITION_SCREENSHOT is not dfeind in AOSP
238     //        HWC guys should fix this.
239 #if 0
240     for (size_t i = 0; i < mLayers.size(); i++) {
241         ExynosLayer *layer = mLayers[i];
242 
243         if (layer->mCompositionType == HWC2_COMPOSITION_SCREENSHOT) {
244             return true;
245         }
246     }
247 #endif
248     return false;
249 }
250 
validateDisplay(uint32_t * outNumTypes,uint32_t * outNumRequests)251 int32_t ExynosExternalDisplay::validateDisplay(
252         uint32_t* outNumTypes, uint32_t* outNumRequests) {
253     Mutex::Autolock lock(mExternalMutex);
254     DISPLAY_LOGD(eDebugExternalDisplay, "");
255 
256     int32_t ret;
257     mSkipFrame = false;
258 
259     if (mSkipStartFrame < SKIP_EXTERNAL_FRAME) {
260         ALOGI("[ExternalDisplay] %s : setGeometryChanged [%d/%d]", __func__, mSkipStartFrame, SKIP_EXTERNAL_FRAME);
261         initDisplay();
262         /*
263          * geometry should be set before ExynosDisplay::validateDisplay is called
264          * not to skip resource assignment
265          */
266         if (mPlugState)
267             setGeometryChanged(GEOMETRY_DEVICE_DISPLAY_ADDED);
268         else
269             setGeometryChanged(GEOMETRY_DEVICE_DISPLAY_REMOVED);
270     }
271 
272     if (handleRotate()) {
273         if ((ret = mResourceManager->initResourcesState(this)) != NO_ERROR)
274             DISPLAY_LOGE("[ExternalDisplay] %s : initResourcesState fail, ret(%d)", __func__, ret);
275         mDevice->setGeometryChanged(GEOMETRY_LAYER_UNKNOWN_CHANGED);
276         mClientCompositionInfo.initializeInfos(this);
277         mExynosCompositionInfo.initializeInfos(this);
278         mRenderingState = RENDERING_STATE_VALIDATED;
279         return HWC2_ERROR_NONE;
280     }
281 
282     if (mSkipStartFrame < SKIP_EXTERNAL_FRAME) {
283         /*
284          * Set mIsSkipFrame before calling ExynosDisplay::validateDisplay()
285          * startPostProcessing() that is called by ExynosDisplay::validateDisplay()
286          * checks mIsSkipFrame.
287          */
288         mIsSkipFrame = true;
289     }
290 
291     ret = ExynosDisplay::validateDisplay(outNumTypes, outNumRequests);
292 
293     if (mSkipStartFrame < SKIP_EXTERNAL_FRAME) {
294         initDisplay();
295         mRenderingState = RENDERING_STATE_VALIDATED;
296         uint32_t changed_count = 0;
297         for (size_t i = 0; i < mLayers.size(); i++) {
298             ExynosLayer *layer = mLayers[i];
299             if (layer &&
300                 (layer->getValidateCompositionType() == HWC2_COMPOSITION_DEVICE ||
301                  layer->getValidateCompositionType() == HWC2_COMPOSITION_EXYNOS)) {
302                 layer->updateValidateCompositionType(HWC2_COMPOSITION_CLIENT, eSkipStartFrame);
303                 layer->mReleaseFence = layer->mAcquireFence;
304                 changed_count++;
305             }
306         }
307         mSkipStartFrame++;
308         *outNumTypes += changed_count;
309 
310         ALOGI("[ExternalDisplay] %s : Skip start frame [%d/%d]", __func__, mSkipStartFrame, SKIP_EXTERNAL_FRAME);
311     }
312 
313     return ret;
314 }
315 
canSkipValidate()316 int32_t ExynosExternalDisplay::canSkipValidate() {
317 
318     /*
319      * SurfaceFlinger may call vadlidate, present for a few frame
320      * even though external display is disconnected.
321      * Cammands for primary display can be discarded if validate is skipped
322      * in this case. HWC should return error not to skip validate.
323      */
324     if ((mHpdStatus == false) || (mBlanked == true))
325         return SKIP_ERR_DISP_NOT_CONNECTED;
326 
327     if ((mSkipStartFrame > (SKIP_EXTERNAL_FRAME - 1)) && (mEnabled == false) &&
328         (mPowerModeState.has_value() &&
329          (*mPowerModeState == (hwc2_power_mode_t)HWC_POWER_MODE_NORMAL)))
330         return SKIP_ERR_DISP_NOT_POWER_ON;
331 
332     if (checkRotate() || (mIsSkipFrame) ||
333         (mSkipStartFrame < SKIP_EXTERNAL_FRAME))
334         return SKIP_ERR_FORCE_VALIDATE;
335 
336     return ExynosDisplay::canSkipValidate();
337 }
338 
presentDisplay(int32_t * outRetireFence)339 int32_t ExynosExternalDisplay::presentDisplay(
340     int32_t* outRetireFence)
341 {
342     Mutex::Autolock lock(mExternalMutex);
343     DISPLAY_LOGD(eDebugExternalDisplay, "");
344     int32_t ret;
345 
346     if (mSkipFrame) {
347         ALOGI("[%d] presentDisplay is skipped by mSkipFrame", mDisplayId);
348         closeFencesForSkipFrame(RENDERING_STATE_PRESENTED);
349         setGeometryChanged(GEOMETRY_DISPLAY_FORCE_VALIDATE);
350         *outRetireFence = -1;
351         for (size_t i=0; i < mLayers.size(); i++) {
352             mLayers[i]->mReleaseFence = -1;
353         }
354         if (mRenderingState == RENDERING_STATE_NONE) {
355             ALOGD("\tThis is the first frame after power on");
356             ret = HWC2_ERROR_NONE;
357         } else {
358             ALOGD("\tThis is the second frame after power on");
359             ret = HWC2_ERROR_NOT_VALIDATED;
360         }
361         mRenderingState = RENDERING_STATE_PRESENTED;
362         mDevice->onRefresh(mDisplayId);
363         return ret;
364     }
365 
366     if ((mIsSkipFrame) || (mHpdStatus == false) || (mBlanked == true)) {
367         if ((exynosHWCControl.skipValidate == true) &&
368             ((mRenderingState == RENDERING_STATE_PRESENTED) ||
369              (mRenderingState == RENDERING_STATE_NONE))) {
370 
371             if (mDevice->canSkipValidate() == false) {
372                 mRenderingState = RENDERING_STATE_NONE;
373                 return HWC2_ERROR_NOT_VALIDATED;
374             } else {
375                 DISPLAY_LOGD(eDebugSkipValidate, "validate is skipped");
376             }
377         }
378 
379         *outRetireFence = -1;
380         for (size_t i = 0; i < mLayers.size(); i++) {
381             ExynosLayer *layer = mLayers[i];
382             layer->mAcquireFence = fence_close(layer->mAcquireFence, this,
383                     FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_LAYER);
384             layer->mReleaseFence = -1;
385         }
386         mClientCompositionInfo.mAcquireFence =
387             fence_close(mClientCompositionInfo.mAcquireFence, this,
388                     FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_FB);
389         mClientCompositionInfo.mReleaseFence = -1;
390 
391         /* this frame is not presented, but mRenderingState is updated to RENDERING_STATE_PRESENTED */
392         initDisplay();
393 
394         /*
395          * Resource assignment information was initialized during skipping frames
396          * So resource assignment for the first displayed frame after skpping frames
397          * should not be skipped
398          */
399         setGeometryChanged(GEOMETRY_DISPLAY_FORCE_VALIDATE);
400 
401         mDevice->onRefresh(mDisplayId);
402 
403         return HWC2_ERROR_NONE;
404     }
405 
406     ret = ExynosDisplay::presentDisplay(outRetireFence);
407 
408     return ret;
409 }
setClientTarget(buffer_handle_t target,int32_t acquireFence,int32_t dataspace)410 int32_t ExynosExternalDisplay::setClientTarget(
411         buffer_handle_t target,
412         int32_t acquireFence, int32_t /*android_dataspace_t*/ dataspace) {
413     buffer_handle_t handle = NULL;
414     if (target != NULL)
415         handle = target;
416     if ((mClientCompositionInfo.mHasCompositionLayer == true) &&
417         (handle == NULL) &&
418         (mClientCompositionInfo.mSkipFlag == false)) {
419         /*
420          * openExternalDisplay() can be called between validateDisplay and getChangedCompositionTypes.
421          * Then getChangedCompositionTypes() returns no layer because openExternalDisplay() clears mLayers.
422          * SurfaceFlinger might not change compositionType to HWC2_COMPOSITION_CLIENT.
423          * Handle can be NULL in this case. It is not error case.
424          */
425         if (mSkipStartFrame == 0) {
426             if (acquireFence >= 0)
427                 fence_close(acquireFence, this, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_FB);
428             acquireFence = -1;
429             mClientCompositionInfo.setTargetBuffer(this, handle, acquireFence, (android_dataspace)dataspace);
430             return NO_ERROR;
431         }
432     }
433     return ExynosDisplay::setClientTarget(target, acquireFence, dataspace);
434 }
435 
enable()436 int ExynosExternalDisplay::enable()
437 {
438     ALOGI("[ExternalDisplay] %s +", __func__);
439 
440     if (mEnabled)
441         return HWC2_ERROR_NONE;
442 
443     if (mHpdStatus == false) {
444         ALOGI("HPD is not connected");
445         return HWC2_ERROR_NONE;
446     }
447 
448     if (openExternalDisplay() < 0)
449         return HWC2_ERROR_UNSUPPORTED;
450 
451     if (mDisplayInterface->setPowerMode(HWC_POWER_MODE_NORMAL) < 0) {
452         DISPLAY_LOGE("set powermode ioctl failed errno : %d", errno);
453         return HWC2_ERROR_UNSUPPORTED;
454     }
455 
456     mEnabled = true;
457     mPowerModeState = (hwc2_power_mode_t)HWC_POWER_MODE_NORMAL;
458     mDisplayInterface->triggerClearDisplayPlanes();
459 
460     reportUsage(true);
461 
462     ALOGI("[ExternalDisplay] %s -", __func__);
463 
464     return HWC2_ERROR_NONE;
465 }
466 
disable()467 int ExynosExternalDisplay::disable()
468 {
469     ALOGI("[ExternalDisplay] %s +", __func__);
470 
471     if (mHpdStatus) {
472         /*
473          * DP cable is connected and link is up
474          *
475          * Currently, we don't power down here for two reasons:
476          * - power up would require DP link re-training (slow)
477          * - DP audio can continue playing while display is blank
478          */
479         if (mEnabled)
480             clearDisplay(false);
481         return HWC2_ERROR_NONE;
482     }
483 
484     if (mSkipStartFrame > (SKIP_EXTERNAL_FRAME - 1)) {
485         clearDisplay(true);
486     } else {
487         ALOGI("Skip clearDisplay to avoid resource conflict");
488     }
489 
490     if (mDisplayInterface->setPowerMode(HWC_POWER_MODE_OFF) < 0) {
491         DISPLAY_LOGE("set powermode ioctl failed errno : %d", errno);
492         return HWC2_ERROR_UNSUPPORTED;
493     }
494 
495     if (mEnabled) reportUsage(false);
496 
497     mEnabled = false;
498     mPowerModeState = (hwc2_power_mode_t)HWC_POWER_MODE_OFF;
499 
500     ALOGI("[ExternalDisplay] %s -", __func__);
501 
502     return HWC2_ERROR_NONE;
503 }
504 
setPowerMode(int32_t mode)505 int32_t ExynosExternalDisplay::setPowerMode(
506         int32_t /*hwc2_power_mode_t*/ mode) {
507     Mutex::Autolock lock(mExternalMutex);
508     {
509         Mutex::Autolock lock(mDisplayMutex);
510 
511         /* TODO state check routine should be added */
512 
513         int fb_blank = 0;
514         int err = 0;
515         if (mode == HWC_POWER_MODE_OFF) {
516             fb_blank = FB_BLANK_POWERDOWN;
517             err = disable();
518         } else if (mode == HWC_POWER_MODE_NORMAL) {
519             fb_blank = FB_BLANK_UNBLANK;
520             err = enable();
521         } else {
522             DISPLAY_LOGE("unsupported powermode: %d", mode);
523             return HWC2_ERROR_UNSUPPORTED;
524         }
525 
526         if (err != 0) {
527             DISPLAY_LOGE("set powermode ioctl failed errno : %d", errno);
528             return HWC2_ERROR_UNSUPPORTED;
529         }
530 
531         if (fb_blank == FB_BLANK_POWERDOWN)
532             mDREnable = false;
533         else if (fb_blank == FB_BLANK_UNBLANK)
534             mDREnable = mDRDefault;
535 
536         // check the dynamic recomposition thread by following display power status
537         mDevice->checkDynamicRecompositionThread();
538 
539         DISPLAY_LOGD(eDebugExternalDisplay, "%s:: mode(%d), blank(%d)", __func__, mode, fb_blank);
540 
541         if (mode == HWC_POWER_MODE_OFF) {
542             /* It should be called from validate() when the screen is on */
543             mSkipFrame = true;
544             setGeometryChanged(GEOMETRY_DISPLAY_POWER_OFF);
545             if ((mRenderingState >= RENDERING_STATE_VALIDATED) &&
546                 (mRenderingState < RENDERING_STATE_PRESENTED))
547                 closeFencesForSkipFrame(RENDERING_STATE_VALIDATED);
548             mRenderingState = RENDERING_STATE_NONE;
549         } else {
550             setGeometryChanged(GEOMETRY_DISPLAY_POWER_ON);
551         }
552     }
553     return HWC2_ERROR_NONE;
554 }
555 
startPostProcessing()556 int32_t ExynosExternalDisplay::startPostProcessing() {
557     if ((mHpdStatus == false) || (mBlanked == true) || mIsSkipFrame) {
558         ALOGI("%s:: skip startPostProcessing display(%d) mHpdStatus(%d)",
559                 __func__, mDisplayId, mHpdStatus);
560         return NO_ERROR;
561     }
562     return ExynosDisplay::startPostProcessing();
563 }
564 
getHDRException(ExynosLayer * __unused layer)565 bool ExynosExternalDisplay::getHDRException(ExynosLayer* __unused layer)
566 {
567     bool ret = false;
568 
569     if (mExternalHdrSupported) {
570         ret = true;
571     }
572     return ret;
573 }
574 
handleHotplugEvent(bool hpdStatus)575 void ExynosExternalDisplay::handleHotplugEvent(bool hpdStatus)
576 {
577     mHpdStatus = hpdStatus;
578     if (mHpdStatus) {
579         if (openExternalDisplay() < 0) {
580             ALOGE("Failed to openExternalDisplay");
581             mHpdStatus = false;
582             return;
583         }
584         mDREnable = mDRDefault;
585     } else {
586         disable();
587         closeExternalDisplay();
588         mDREnable = false;
589     }
590     mDevice->checkDynamicRecompositionThread();
591 
592     ALOGI("HPD status changed to %s, mDisplayId %d, mDisplayFd %d", mHpdStatus ? "enabled" : "disabled", mDisplayId, mDisplayInterface->getDisplayFd());
593 }
594 
initDisplayInterface(uint32_t interfaceType)595 void ExynosExternalDisplay::initDisplayInterface(uint32_t interfaceType)
596 {
597     if (interfaceType == INTERFACE_TYPE_DRM)
598         mDisplayInterface = std::make_unique<ExynosExternalDisplayDrmInterfaceModule>((ExynosDisplay *)this);
599     else
600         LOG_ALWAYS_FATAL("%s::Unknown interface type(%d)",
601                 __func__, interfaceType);
602     mDisplayInterface->init(this);
603 }
604 
reportUsage(bool enabled)605 void ExynosExternalDisplay::reportUsage(bool enabled) {
606     auto refreshRate = nanoSec2Hz(mVsyncPeriod);
607     auto manufacturerInfo = mDisplayInterface->getManufacturerInfo();
608     auto productId = mDisplayInterface->getProductId();
609 
610     ATRACE_NAME("report ext usage");
611     reportDisplayPortUsage(mXres, mYres, refreshRate, manufacturerInfo, productId, enabled);
612 }
613