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