2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 #include <sys/types.h>
21 #include <utils/Trace.h>
28 #include "ExynosHWCService.h"
30 class ExynosHWCService
;
35 #include "ExynosIPService.h"
38 #include "ExynosHWC.h"
39 #include "ExynosHWCUtils.h"
40 #include "ExynosMPPModule.h"
41 #include "ExynosOverlayDisplay.h"
42 #include "ExynosExternalDisplayModule.h"
43 #include "ExynosPrimaryDisplay.h"
44 #if defined(USES_DUAL_DISPLAY)
45 #include "ExynosSecondaryDisplayModule.h"
47 #ifdef USES_VIRTUAL_DISPLAY
48 #include "ExynosVirtualDisplayModule.h"
51 void doPSRExit(struct exynos5_hwc_composer_device_1_t
*pdev
)
55 if (pdev
->psrMode
!= PSR_NONE
&& pdev
->notifyPSRExit
) {
56 pdev
->notifyPSRExit
= false;
57 ret
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, S3CFB_WIN_PSR_EXIT
, &val
);
62 void handle_cec(exynos5_hwc_composer_device_1_t
*pdev
)
64 unsigned char buffer
[16];
66 unsigned char lsrc
, ldst
, opcode
;
68 size
= CECReceiveMessage(buffer
, CEC_MAX_FRAME_SIZE
, 1000);
70 /* no data available or ctrl-c */
74 /* "Polling Message" */
78 lsrc
= buffer
[0] >> 4;
80 /* ignore messages with src address == mCecLaddr */
81 if (lsrc
== pdev
->mCecLaddr
)
86 if (CECIgnoreMessage(opcode
, lsrc
)) {
87 ALOGE("### ignore message coming from address 15 (unregistered)");
91 if (!CECCheckMessageSize(opcode
, size
)) {
93 * For some reason the TV sometimes sends messages that are too long
94 * Dropping these causes the connect process to fail, so for now we
95 * simply ignore the extra data and process the message as if it had
98 ALOGD("### invalid message size: %d(opcode: 0x%x) ###", size
, opcode
);
101 /* check if message broadcasted/directly addressed */
102 if (!CECCheckMessageMode(opcode
, (buffer
[0] & 0x0F) == CEC_MSG_BROADCAST
? 1 : 0)) {
103 ALOGE("### invalid message mode (directly addressed/broadcast) ###");
109 /* TODO: macros to extract src and dst logical addresses */
110 /* TODO: macros to extract opcode */
113 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS
:
114 /* respond with "Report Physical Address" */
115 buffer
[0] = (pdev
->mCecLaddr
<< 4) | CEC_MSG_BROADCAST
;
116 buffer
[1] = CEC_OPCODE_REPORT_PHYSICAL_ADDRESS
;
117 buffer
[2] = (pdev
->mCecPaddr
>> 8) & 0xFF;
118 buffer
[3] = pdev
->mCecPaddr
& 0xFF;
123 case CEC_OPCODE_SET_STREAM_PATH
:
124 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE
:
125 /* respond with "Active Source" */
126 buffer
[0] = (pdev
->mCecLaddr
<< 4) | CEC_MSG_BROADCAST
;
127 buffer
[1] = CEC_OPCODE_ACTIVE_SOURCE
;
128 buffer
[2] = (pdev
->mCecPaddr
>> 8) & 0xFF;
129 buffer
[3] = pdev
->mCecPaddr
& 0xFF;
133 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS
:
134 /* respond with "Report Power Status" */
135 buffer
[0] = (pdev
->mCecLaddr
<< 4) | ldst
;
136 buffer
[1] = CEC_OPCODE_REPORT_POWER_STATUS
;
141 case CEC_OPCODE_REPORT_POWER_STATUS
:
142 /* send Power On message */
143 buffer
[0] = (pdev
->mCecLaddr
<< 4) | ldst
;
144 buffer
[1] = CEC_OPCODE_USER_CONTROL_PRESSED
;
149 case CEC_OPCODE_USER_CONTROL_PRESSED
:
150 buffer
[0] = (pdev
->mCecLaddr
<< 4) | ldst
;
153 case CEC_OPCODE_GIVE_DECK_STATUS
:
154 /* respond with "Deck Status" */
155 buffer
[0] = (pdev
->mCecLaddr
<< 4) | ldst
;
156 buffer
[1] = CEC_OPCODE_DECK_STATUS
;
161 case CEC_OPCODE_ABORT
:
162 case CEC_OPCODE_FEATURE_ABORT
:
164 /* send "Feature Abort" */
165 buffer
[0] = (pdev
->mCecLaddr
<< 4) | ldst
;
166 buffer
[1] = CEC_OPCODE_FEATURE_ABORT
;
167 buffer
[2] = CEC_OPCODE_ABORT
;
173 if (CECSendMessage(buffer
, size
) != size
)
174 ALOGE("CECSendMessage() failed!!!");
177 void start_cec(exynos5_hwc_composer_device_1_t
*pdev
)
179 unsigned char buffer
[CEC_MAX_FRAME_SIZE
];
181 pdev
->mCecFd
= CECOpen();
182 pdev
->mCecPaddr
= CEC_NOT_VALID_PHYSICAL_ADDRESS
;
183 pdev
->mCecPaddr
= pdev
->externalDisplay
->getCecPaddr();
184 if (pdev
->mCecPaddr
< 0) {
185 ALOGE("Error getting physical address");
188 pdev
->mCecLaddr
= CECAllocLogicalAddress(pdev
->mCecPaddr
, CEC_DEVICE_PLAYER
);
189 /* Request power state from TV */
190 buffer
[0] = (pdev
->mCecLaddr
<< 4);
191 buffer
[1] = CEC_OPCODE_GIVE_DEVICE_POWER_STATUS
;
193 if (CECSendMessage(buffer
, size
) != size
)
194 ALOGE("CECSendMessage(%#x) failed!!!", buffer
[0]);
198 void exynos5_boot_finished(exynos5_hwc_composer_device_1_t
*dev
)
200 ALOGD("Boot Finished");
202 exynos5_hwc_composer_device_1_t
*pdev
=
203 (exynos5_hwc_composer_device_1_t
*)dev
;
205 ALOGE("%s:: dev is NULL", __func__
);
208 sw_fd
= open("/sys/class/switch/hdmi/state", O_RDONLY
);
212 if (read(sw_fd
, &val
, 1) == 1 && val
== '1') {
213 if (pdev
->hdmi_hpd
!= 1) {
214 pdev
->hdmi_hpd
= true;
215 if ((pdev
->externalDisplay
->openHdmi() > 0) && pdev
->externalDisplay
->getConfig()) {
216 ALOGE("Error reading HDMI configuration");
217 pdev
->hdmi_hpd
= false;
219 pdev
->externalDisplay
->mBlanked
= false;
220 #if defined(USES_CEC)
224 pdev
->procs
->hotplug(pdev
->procs
, HWC_DISPLAY_EXTERNAL
, true);
225 pdev
->procs
->invalidate(pdev
->procs
);
233 int exynos5_prepare(hwc_composer_device_1_t
*dev
,
234 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
237 if (!numDisplays
|| !displays
)
240 exynos5_hwc_composer_device_1_t
*pdev
=
241 (exynos5_hwc_composer_device_1_t
*)dev
;
242 #if defined(USES_DUAL_DISPLAY)
243 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY0
];
244 hwc_display_contents_1_t
*fimd_contents1
= displays
[HWC_DISPLAY_PRIMARY1
];
246 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
249 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
250 #ifdef USES_VIRTUAL_DISPLAY
251 hwc_display_contents_1_t
*virtual_contents
= displays
[HWC_DISPLAY_VIRTUAL
];
252 if (virtual_contents
== NULL
)
253 pdev
->virtualDisplay
->deInit();
254 #ifdef USES_VIRTUAL_DISPLAY_DECON_EXT_WB
255 if (virtual_contents
)
256 pdev
->virtualDisplay
->init(virtual_contents
);
259 pdev
->updateCallCnt
++;
260 pdev
->update_event_cnt
++;
261 pdev
->LastUpdateTimeStamp
= systemTime(SYSTEM_TIME_MONOTONIC
);
262 pdev
->primaryDisplay
->getCompModeSwitch();
264 pdev
->incomingPixels
= 0;
266 #if defined(USES_DUAL_DISPLAY)
267 if (pdev
->hdmi_hpd
|| (fimd_contents1
== NULL
) ||
268 (fimd_contents1
->numHwLayers
<= 1)) {
269 if (pdev
->secondaryDisplay
->mEnabled
)
270 pdev
->secondaryDisplay
->disable();
274 pdev
->externalDisplay
->setHdmiStatus(pdev
->hdmi_hpd
);
276 #if defined(USES_DUAL_DISPLAY)
277 if (!pdev
->hdmi_hpd
&& fimd_contents1
&&
278 (fimd_contents1
->numHwLayers
> 1)) {
279 if (!pdev
->secondaryDisplay
->mEnabled
)
280 pdev
->secondaryDisplay
->enable();
284 if (pdev
->hwc_ctrl
.dynamic_recomp_mode
== true &&
285 pdev
->update_stat_thread_flag
== false &&
286 pdev
->primaryDisplay
->mBlanked
== false) {
287 exynos5_create_update_stat_thread(pdev
);
291 pdev
->mDisplayResourceManager
->assignResources(numDisplays
, displays
);
295 android::Mutex::Autolock
lock(pdev
->primaryDisplay
->mLayerInfoMutex
);
296 int err
= pdev
->primaryDisplay
->prepare(fimd_contents
);
301 android::Mutex::Autolock
lock(pdev
->externalDisplay
->mLayerInfoMutex
);
303 err
= pdev
->externalDisplay
->prepare(hdmi_contents
);
307 #if defined(USES_DUAL_DISPLAY)
308 if ((pdev
->hdmi_hpd
== false) && fimd_contents1
) {
309 android::Mutex::Autolock
lock(pdev
->secondaryDisplay
->mLayerInfoMutex
);
310 int err
= pdev
->secondaryDisplay
->prepare(fimd_contents1
);
317 #ifdef USES_VIRTUAL_DISPLAY
318 if (virtual_contents
) {
319 #ifdef USES_VIRTUAL_DISPLAY_DECON_EXT_WB
320 ExynosVirtualDisplayModule
*virDisplay
= (ExynosVirtualDisplayModule
*)pdev
->virtualDisplay
;
321 virDisplay
->setPriContents(fimd_contents
);
323 int err
= pdev
->virtualDisplay
->prepare(virtual_contents
);
332 int exynos5_set(struct hwc_composer_device_1
*dev
,
333 size_t numDisplays
, hwc_display_contents_1_t
** displays
)
336 if (!numDisplays
|| !displays
)
339 exynos5_hwc_composer_device_1_t
*pdev
=
340 (exynos5_hwc_composer_device_1_t
*)dev
;
341 #if defined(USES_DUAL_DISPLAY)
342 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY0
];
343 hwc_display_contents_1_t
*fimd_contents1
= displays
[HWC_DISPLAY_PRIMARY1
];
345 hwc_display_contents_1_t
*fimd_contents
= displays
[HWC_DISPLAY_PRIMARY
];
347 hwc_display_contents_1_t
*hdmi_contents
= displays
[HWC_DISPLAY_EXTERNAL
];
348 int fimd_err
= 0, hdmi_err
= 0;
349 #ifdef USES_VIRTUAL_DISPLAY
351 hwc_display_contents_1_t
*virtual_contents
= displays
[HWC_DISPLAY_VIRTUAL
];
354 #if defined(USES_DUAL_DISPLAY)
355 if ((pdev
->hdmi_hpd
== false) && fimd_contents1
) {
356 hdmi_err
= pdev
->secondaryDisplay
->set(fimd_contents1
);
361 android::Mutex::Autolock
lock(pdev
->primaryDisplay
->mLayerInfoMutex
);
362 #if defined(USES_DUAL_DISPLAY)
363 fimd_err
= pdev
->primaryDisplay
->set_dual(fimd_contents
, fimd_contents1
);
365 fimd_err
= pdev
->primaryDisplay
->set(fimd_contents
);
369 if (pdev
->mS3DMode
!= S3D_MODE_STOPPING
&& !pdev
->mHdmiResolutionHandled
) {
370 pdev
->mHdmiResolutionHandled
= true;
371 pdev
->hdmi_hpd
= true;
372 pdev
->externalDisplay
->enable();
374 pdev
->procs
->hotplug(pdev
->procs
, HWC_DISPLAY_EXTERNAL
, true);
375 pdev
->procs
->invalidate(pdev
->procs
);
379 if (hdmi_contents
&& fimd_contents
) {
380 android::Mutex::Autolock
lock(pdev
->externalDisplay
->mLayerInfoMutex
);
381 hdmi_err
= pdev
->externalDisplay
->set(hdmi_contents
);
384 if (pdev
->hdmi_hpd
&& pdev
->mHdmiResolutionChanged
) {
385 if (pdev
->mS3DMode
== S3D_MODE_DISABLED
&& pdev
->externalDisplay
->isPresetSupported(pdev
->mHdmiPreset
))
386 pdev
->externalDisplay
->setPreset(pdev
->mHdmiPreset
);
388 if (pdev
->mS3DMode
== S3D_MODE_STOPPING
) {
389 pdev
->mS3DMode
= S3D_MODE_DISABLED
;
391 for (int i
= 0; i
< pdev
->primaryDisplay
->mNumMPPs
; i
++)
392 pdev
->primaryDisplay
->mMPPs
[i
]->mS3DMode
= S3D_NONE
;
394 if (pdev
->externalDisplay
->mMPPs
[0] != NULL
)
395 pdev
->externalDisplay
->mMPPs
[0]->mS3DMode
= S3D_NONE
;
399 #ifdef USES_VIRTUAL_DISPLAY
400 if (virtual_contents
&& fimd_contents
)
401 virtual_err
= pdev
->virtualDisplay
->set(virtual_contents
);
404 #ifdef EXYNOS_SUPPORT_PSR_EXIT
405 pdev
->notifyPSRExit
= true;
407 pdev
->notifyPSRExit
= false;
410 pdev
->primaryDisplay
->freeMPP();
413 pdev
->mDisplayResourceManager
->cleanupMPPs();
419 #ifndef USES_VIRTUAL_DISPLAY
429 void exynos5_registerProcs(struct hwc_composer_device_1
* dev
,
430 hwc_procs_t
const* procs
)
432 struct exynos5_hwc_composer_device_1_t
* pdev
=
433 (struct exynos5_hwc_composer_device_1_t
*)dev
;
437 int exynos5_query(struct hwc_composer_device_1
* dev
, int what
, int *value
)
439 struct exynos5_hwc_composer_device_1_t
*pdev
=
440 (struct exynos5_hwc_composer_device_1_t
*)dev
;
443 case HWC_BACKGROUND_LAYER_SUPPORTED
:
444 // we do not support the background layer
447 case HWC_VSYNC_PERIOD
:
448 // vsync period in nanosecond
449 value
[0] = pdev
->primaryDisplay
->mVsyncPeriod
;
458 int exynos5_eventControl(struct hwc_composer_device_1
*dev
, int __unused dpy
,
459 int event
, int enabled
)
461 struct exynos5_hwc_composer_device_1_t
*pdev
=
462 (struct exynos5_hwc_composer_device_1_t
*)dev
;
465 case HWC_EVENT_VSYNC
:
466 __u32 val
= !!enabled
;
467 pdev
->VsyncInterruptStatus
= val
;
468 int err
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, S3CFB_SET_VSYNC_INT
, &val
);
470 ALOGE("vsync ioctl failed");
479 void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t
*pdev
,
480 const char *buff
, int len
)
482 const char *s
= buff
;
486 if (!strncmp(s
, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
487 pdev
->hdmi_hpd
= atoi(s
+ strlen("SWITCH_STATE=")) == 1;
494 if (pdev
->hdmi_hpd
) {
495 if ((pdev
->externalDisplay
->openHdmi() > 0) && pdev
->externalDisplay
->getConfig()) {
496 ALOGE("Error reading HDMI configuration");
497 pdev
->hdmi_hpd
= false;
501 pdev
->externalDisplay
->mBlanked
= false;
502 #if defined(USES_CEC)
512 ALOGV("HDMI HPD changed to %s", pdev
->hdmi_hpd
? "enabled" : "disabled");
514 ALOGI("HDMI Resolution changed to %dx%d",
515 pdev
->externalDisplay
->mXres
, pdev
->externalDisplay
->mYres
);
517 /* hwc_dev->procs is set right after the device is opened, but there is
518 * still a race condition where a hotplug event might occur after the open
519 * but before the procs are registered. */
521 pdev
->procs
->hotplug(pdev
->procs
, HWC_DISPLAY_EXTERNAL
, pdev
->hdmi_hpd
);
524 void handle_tui_uevent(struct exynos5_hwc_composer_device_1_t
*pdev __unused
,
525 const char *buff __unused
, int len __unused
)
528 #ifdef DISABLE_IDMA_SECURE
531 const char *s
= buff
;
532 unsigned int tui_disabled
= 1;
533 bool useSecureDMA
= true;
537 if (!strncmp(s
, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
538 tui_disabled
= atoi(s
+ strlen("SWITCH_STATE=")) == 0;
548 useSecureDMA
= false;
550 ALOGI("TUI mode is %s", tui_disabled
? "disabled" : "enabled");
552 if (pdev
->primaryDisplay
->mUseSecureDMA
!= useSecureDMA
) {
553 pdev
->primaryDisplay
->mUseSecureDMA
= useSecureDMA
;
554 if ((pdev
->procs
) && (pdev
->procs
->invalidate
))
555 pdev
->procs
->invalidate(pdev
->procs
);
561 void handle_vsync_event(struct exynos5_hwc_composer_device_1_t
*pdev
)
566 int err
= lseek(pdev
->vsync_fd
, 0, SEEK_SET
);
568 ALOGE("error seeking to vsync timestamp: %s", strerror(errno
));
573 err
= read(pdev
->vsync_fd
, buf
, sizeof(buf
));
575 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
578 buf
[sizeof(buf
) - 1] = '\0';
581 uint64_t timestamp
= strtoull(buf
, NULL
, 0);
583 pdev
->procs
->vsync(pdev
->procs
, 0, timestamp
);
586 void *hwc_update_stat_thread(void *data
)
588 struct exynos5_hwc_composer_device_1_t
*pdev
=
589 (struct exynos5_hwc_composer_device_1_t
*)data
;
592 while (pdev
->update_stat_thread_flag
) {
593 event_cnt
= pdev
->update_event_cnt
;
595 * If there is no update for more than 100ms, favor the 3D composition mode.
596 * If all other conditions are met, mode will be switched to 3D composition.
599 if (event_cnt
== pdev
->update_event_cnt
) {
600 if (pdev
->primaryDisplay
->getCompModeSwitch() == HWC_2_GLES
) {
601 if ((pdev
->procs
) && (pdev
->procs
->invalidate
)) {
602 pdev
->update_event_cnt
= 0;
603 pdev
->procs
->invalidate(pdev
->procs
);
611 void exynos5_create_update_stat_thread(struct exynos5_hwc_composer_device_1_t
*dev
)
613 /* pthread_create shouldn't have ben failed. But, ignore even if some error */
614 if (pthread_create(&dev
->update_stat_thread
, NULL
, hwc_update_stat_thread
, dev
) != 0) {
615 ALOGE("%s: failed to start update_stat thread:", __func__
);
616 dev
->update_stat_thread_flag
= false;
618 dev
->update_stat_thread_flag
= true;
622 void *hwc_vsync_thread(void *data
)
624 struct exynos5_hwc_composer_device_1_t
*pdev
=
625 (struct exynos5_hwc_composer_device_1_t
*)data
;
626 char uevent_desc
[4096];
627 memset(uevent_desc
, 0, sizeof(uevent_desc
));
629 setpriority(PRIO_PROCESS
, 0, HAL_PRIORITY_URGENT_DISPLAY
);
634 int err
= read(pdev
->vsync_fd
, temp
, sizeof(temp
));
636 ALOGE("error reading vsync timestamp: %s", strerror(errno
));
640 #if defined(USES_CEC)
641 struct pollfd fds
[3];
643 struct pollfd fds
[2];
645 fds
[0].fd
= pdev
->vsync_fd
;
646 fds
[0].events
= POLLPRI
;
647 fds
[1].fd
= uevent_get_fd();
648 fds
[1].events
= POLLIN
;
649 #if defined(USES_CEC)
650 fds
[2].fd
= pdev
->mCecFd
;
651 fds
[2].events
= POLLIN
;
655 #if defined(USES_CEC)
657 fds
[2].fd
= pdev
->mCecFd
;
659 err
= poll(fds
, 3, -1);
661 err
= poll(fds
, 2, -1);
663 int err
= poll(fds
, 2, -1);
667 if (fds
[0].revents
& POLLPRI
) {
668 handle_vsync_event(pdev
);
670 else if (fds
[1].revents
& POLLIN
) {
671 int len
= uevent_next_event(uevent_desc
,
672 sizeof(uevent_desc
) - 2);
674 bool hdmi
= !strcmp(uevent_desc
,
675 "change@/devices/virtual/switch/hdmi");
676 bool tui_status
= !strcmp(uevent_desc
,
677 "change@/devices/virtual/switch/tui");
680 handle_hdmi_uevent(pdev
, uevent_desc
, len
);
682 handle_tui_uevent(pdev
, uevent_desc
, len
);
683 #if defined(USES_CEC)
684 } else if (pdev
->hdmi_hpd
&& fds
[2].revents
& POLLIN
) {
689 else if (err
== -1) {
692 ALOGE("error in vsync thread: %s", strerror(errno
));
699 int exynos5_blank(struct hwc_composer_device_1
*dev
, int disp
, int blank
)
702 struct exynos5_hwc_composer_device_1_t
*pdev
=
703 (struct exynos5_hwc_composer_device_1_t
*)dev
;
704 #ifdef SKIP_DISPLAY_BLANK_CTRL
707 ALOGI("%s:: disp(%d), blank(%d)", __func__
, disp
, blank
);
709 case HWC_DISPLAY_PRIMARY
: {
710 int fb_blank
= blank
? FB_BLANK_POWERDOWN
: FB_BLANK_UNBLANK
;
711 if (fb_blank
== FB_BLANK_POWERDOWN
) {
712 int fence
= pdev
->primaryDisplay
->clearDisplay();
714 HLOGE("error clearing primary display");
717 if (pdev
->primaryDisplay
->mGscUsed
&& pdev
->primaryDisplay
->mMPPs
[FIMD_GSC_IDX
]->isOTF())
718 pdev
->primaryDisplay
->mMPPs
[FIMD_GSC_IDX
]->cleanupOTF();
723 #if !defined(HDMI_ON_IN_SUSPEND) && defined(CHANGE_POWEROFF_SEQ)
725 * LCD power block shouldn't be turned off
726 * before TV power block is turned off in Exynos4.
728 if (pdev
->hdmi_hpd
) {
729 if (blank
&& !pdev
->externalDisplay
->mBlanked
) {
730 pdev
->externalDisplay
->disable();
732 pdev
->externalDisplay
->mBlanked
= !!blank
;
735 pdev
->primaryDisplay
->mBlanked
= !!blank
;
737 /* Check if the thread is enabled before calling pthread_kill as we will seg fault otherwise */
738 if(pdev
->update_stat_thread_flag
== true) {
739 if (pthread_kill(pdev
->update_stat_thread
, 0) != ESRCH
) { //check if the thread is alive
740 if (fb_blank
== FB_BLANK_POWERDOWN
) {
741 pdev
->update_stat_thread_flag
= false;
742 pthread_join(pdev
->update_stat_thread
, 0);
745 } else { // thread is not alive
746 if (fb_blank
== FB_BLANK_UNBLANK
&& pdev
->hwc_ctrl
.dynamic_recomp_mode
== true)
747 exynos5_create_update_stat_thread(pdev
);
749 #if defined(USES_DUAL_DISPLAY)
750 struct decon_dual_display_blank_data blank_data
;
751 memset(&blank_data
, 0, sizeof(blank_data
));
752 blank_data
.display_type
= blank_data
.DECON_PRIMARY_DISPLAY
;
753 blank_data
.blank
= fb_blank
;
754 int err
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, S3CFB_DUAL_DISPLAY_BLANK
, &blank_data
);
756 int err
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, FBIOBLANK
, fb_blank
);
760 ALOGI("%sblank ioctl failed (display already %sblanked)",
761 blank
? "" : "un", blank
? "" : "un");
763 ALOGE("%sblank ioctl failed: %s", blank
? "" : "un",
769 #if defined(USES_DUAL_DISPLAY)
770 case HWC_DISPLAY_PRIMARY1
: {
771 int fb_blank
= blank
? FB_BLANK_POWERDOWN
: FB_BLANK_UNBLANK
;
772 /* To do: Should be implemented */
773 pdev
->secondaryDisplay
->mBlanked
= !!blank
;
774 struct decon_dual_display_blank_data blank_data
;
775 memset(&blank_data
, 0, sizeof(blank_data
));
776 blank_data
.display_type
= blank_data
.DECON_SECONDARY_DISPLAY
;
777 blank_data
.blank
= fb_blank
;
778 int err
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, S3CFB_DUAL_DISPLAY_BLANK
, &blank_data
);
782 case HWC_DISPLAY_EXTERNAL
:
783 #if !defined(HDMI_ON_IN_SUSPEND) && !defined(CHANGE_POWEROFF_SEQ)
784 if (pdev
->hdmi_hpd
) {
785 if (blank
&& !pdev
->externalDisplay
->mBlanked
) {
786 pdev
->externalDisplay
->disable();
788 pdev
->externalDisplay
->mBlanked
= !!blank
;
791 fence
= pdev
->externalDisplay
->clearDisplay();
794 pdev
->externalDisplay
->mBlanked
= !!blank
;
806 void exynos5_dump(hwc_composer_device_1
* dev
, char *buff
, int buff_len
)
811 struct exynos5_hwc_composer_device_1_t
*pdev
=
812 (struct exynos5_hwc_composer_device_1_t
*)dev
;
814 android::String8 result
;
816 result
.appendFormat("\n hdmi_enabled=%u\n", pdev
->externalDisplay
->mEnabled
);
817 if (pdev
->externalDisplay
->mEnabled
)
818 result
.appendFormat(" w=%u, h=%u\n", pdev
->externalDisplay
->mXres
, pdev
->externalDisplay
->mYres
);
820 result
.append("Primary device's config information\n");
821 pdev
->primaryDisplay
->dump(result
);
824 if (pdev
->hdmi_hpd
) {
826 result
.append("External device's config information\n");
827 pdev
->externalDisplay
->dump(result
);
829 #if defined(USES_DUAL_DISPLAY)
832 result
.append("Secondary device's config information\n");
833 pdev
->secondaryDisplay
->dump(result
);
836 #ifdef USES_VIRTUAL_DISPLAY_DECON_EXT_WB
837 if (pdev
->virtualDisplay
->mIsWFDState
) {
839 result
.append("Virtual device's config information\n");
840 pdev
->virtualDisplay
->dump(result
);
845 android::Mutex::Autolock
lock(pdev
->primaryDisplay
->mLayerInfoMutex
);
847 result
.append("Primary device's layer information\n");
848 pdev
->primaryDisplay
->dumpLayerInfo(result
);
851 if (pdev
->hdmi_hpd
) {
852 android::Mutex::Autolock
lock(pdev
->externalDisplay
->mLayerInfoMutex
);
854 result
.append("External device's layer information\n");
855 pdev
->externalDisplay
->dumpLayerInfo(result
);
857 #if defined(USES_DUAL_DISPLAY)
859 android::Mutex::Autolock
lock(pdev
->secondaryDisplay
->mLayerInfoMutex
);
861 result
.append("Secondary device's layer information\n");
862 pdev
->secondaryDisplay
->dumpLayerInfo(result
);
865 #if USES_VIRTUAL_DISPLAY_DECON_EXT_WB
866 if (pdev
->virtualDisplay
->mIsWFDState
) {
867 android::Mutex::Autolock
lock(pdev
->virtualDisplay
->mLayerInfoMutex
);
869 result
.append("Virtual device's layer information\n");
870 pdev
->virtualDisplay
->dumpLayerInfo(result
);
873 strlcpy(buff
, result
.string(), buff_len
);
876 int exynos5_getDisplayConfigs(struct hwc_composer_device_1
*dev
,
877 int disp
, uint32_t *configs
, size_t *numConfigs
)
879 struct exynos5_hwc_composer_device_1_t
*pdev
=
880 (struct exynos5_hwc_composer_device_1_t
*)dev
;
883 if (*numConfigs
== 0)
886 #if defined(USES_DUAL_DISPLAY)
887 if (disp
== HWC_DISPLAY_PRIMARY0
) {
891 } else if (disp
== HWC_DISPLAY_PRIMARY1
) {
896 if (disp
== HWC_DISPLAY_PRIMARY
) {
901 } else if (disp
== HWC_DISPLAY_EXTERNAL
) {
902 if (!pdev
->hdmi_hpd
) {
905 if (hwcHasApiVersion((hwc_composer_device_1_t
*)dev
, HWC_DEVICE_API_VERSION_1_4
))
906 err
= pdev
->externalDisplay
->getDisplayConfigs(configs
, numConfigs
);
908 err
= pdev
->externalDisplay
->getConfig();
916 #ifdef USES_VIRTUAL_DISPLAY
917 } else if (disp
== HWC_DISPLAY_VIRTUAL
) {
918 int err
= pdev
->virtualDisplay
->getConfig();
931 int32_t exynos5_hdmi_attribute(struct exynos5_hwc_composer_device_1_t
*pdev
,
932 const uint32_t attribute
)
935 case HWC_DISPLAY_VSYNC_PERIOD
:
936 return pdev
->primaryDisplay
->mVsyncPeriod
;
938 case HWC_DISPLAY_WIDTH
:
939 return pdev
->externalDisplay
->mXres
;
941 case HWC_DISPLAY_HEIGHT
:
942 return pdev
->externalDisplay
->mYres
;
944 case HWC_DISPLAY_DPI_X
:
945 case HWC_DISPLAY_DPI_Y
:
949 ALOGE("unknown display attribute %u", attribute
);
954 int exynos5_getDisplayAttributes(struct hwc_composer_device_1
*dev
,
955 int disp
, uint32_t config
, const uint32_t *attributes
, int32_t *values
)
957 struct exynos5_hwc_composer_device_1_t
*pdev
=
958 (struct exynos5_hwc_composer_device_1_t
*)dev
;
960 for (int i
= 0; attributes
[i
] != HWC_DISPLAY_NO_ATTRIBUTE
; i
++) {
961 #if defined(USES_DUAL_DISPLAY)
962 if (disp
== HWC_DISPLAY_PRIMARY0
)
963 values
[i
] = pdev
->primaryDisplay
->getDisplayAttributes(attributes
[i
]);
964 else if (disp
== HWC_DISPLAY_PRIMARY1
)
965 values
[i
] = pdev
->secondaryDisplay
->getDisplayAttributes(attributes
[i
]);
967 if (disp
== HWC_DISPLAY_PRIMARY
)
968 values
[i
] = pdev
->primaryDisplay
->getDisplayAttributes(attributes
[i
], config
);
970 else if (disp
== HWC_DISPLAY_EXTERNAL
) {
971 if (hwcHasApiVersion((hwc_composer_device_1_t
*)dev
, HWC_DEVICE_API_VERSION_1_4
))
972 values
[i
] = pdev
->externalDisplay
->getDisplayAttributes(attributes
[i
], config
);
974 values
[i
] = exynos5_hdmi_attribute(pdev
, attributes
[i
]);
976 #ifdef USES_VIRTUAL_DISPLAY
977 else if (disp
== HWC_DISPLAY_VIRTUAL
)
978 values
[i
] = pdev
->virtualDisplay
->getDisplayAttributes(attributes
[i
]);
981 ALOGE("unknown display type %u", disp
);
989 int exynos_getActiveConfig(struct hwc_composer_device_1
* dev
, int disp
)
991 struct exynos5_hwc_composer_device_1_t
*pdev
=
992 (struct exynos5_hwc_composer_device_1_t
*)dev
;
993 if (disp
== HWC_DISPLAY_PRIMARY
)
995 else if (disp
== HWC_DISPLAY_EXTERNAL
) {
996 if (pdev
->hdmi_hpd
) {
997 if (hwcHasApiVersion((hwc_composer_device_1_t
*)dev
, HWC_DEVICE_API_VERSION_1_4
))
998 return pdev
->externalDisplay
->getActiveConfig();
1002 ALOGE("%s::External device is not connected", __func__
);
1005 } else if (disp
== HWC_DISPLAY_VIRTUAL
)
1008 ALOGE("%s:: unknown display type %u", __func__
, disp
);
1013 int exynos_setActiveConfig(struct hwc_composer_device_1
* dev
, int disp
, int index
)
1015 struct exynos5_hwc_composer_device_1_t
*pdev
=
1016 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1017 ALOGI("%s:: disp(%d), index(%d)", __func__
, disp
, index
);
1018 if (disp
== HWC_DISPLAY_PRIMARY
) {
1020 ALOGE("%s::Primary display doen't support index(%d)", __func__
, index
);
1025 else if (disp
== HWC_DISPLAY_EXTERNAL
) {
1026 if (pdev
->hdmi_hpd
) {
1027 if (hwcHasApiVersion((hwc_composer_device_1_t
*)dev
, HWC_DEVICE_API_VERSION_1_4
)) {
1028 return pdev
->externalDisplay
->setActiveConfig(index
);
1031 ALOGE("%s::External display doen't support index(%d)", __func__
, index
);
1038 ALOGE("%s::External device is not connected", __func__
);
1041 } else if (disp
== HWC_DISPLAY_VIRTUAL
)
1047 int exynos_setCursorPositionAsync(struct hwc_composer_device_1
*dev __unused
, int disp __unused
, int x_pos __unused
, int y_pos __unused
)
1052 int exynos_setPowerMode(struct hwc_composer_device_1
* dev
, int disp
, int mode
)
1055 struct exynos5_hwc_composer_device_1_t
*pdev
=
1056 (struct exynos5_hwc_composer_device_1_t
*)dev
;
1057 #ifdef SKIP_DISPLAY_BLANK_CTRL
1060 ALOGI("%s:: disp(%d), mode(%d)", __func__
, disp
, mode
);
1063 if (mode
== HWC_POWER_MODE_OFF
) {
1064 fb_blank
= FB_BLANK_POWERDOWN
;
1067 fb_blank
= FB_BLANK_UNBLANK
;
1072 case HWC_DISPLAY_PRIMARY
: {
1074 if ((mode
== HWC_POWER_MODE_DOZE
) || (mode
== HWC_POWER_MODE_DOZE_SUSPEND
)) {
1075 if (pdev
->primaryDisplay
->mBlanked
== 1) {
1076 fb_blank
= FB_BLANK_UNBLANK
;
1077 int err
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, FBIOBLANK
, fb_blank
);
1079 ALOGE("blank ioctl failed: %s, mode(%d)", strerror(errno
), mode
);
1083 pdev
->primaryDisplay
->mBlanked
= 0;
1084 return pdev
->primaryDisplay
->setPowerMode(mode
);
1087 if (fb_blank
== FB_BLANK_POWERDOWN
) {
1089 #if defined(USES_DUAL_DISPLAY)
1090 if (pdev
->secondaryDisplay
->mBlanked
)
1092 fence
= pdev
->primaryDisplay
->clearDisplay();
1094 HLOGE("error clearing primary display");
1097 if (pdev
->primaryDisplay
->mGscUsed
&& pdev
->primaryDisplay
->mMPPs
[FIMD_GSC_IDX
]->isOTF())
1098 pdev
->primaryDisplay
->mMPPs
[FIMD_GSC_IDX
]->cleanupOTF();
1103 #if !defined(HDMI_ON_IN_SUSPEND) && defined(CHANGE_POWEROFF_SEQ)
1105 * LCD power block shouldn't be turned off
1106 * before TV power block is turned off in Exynos4.
1108 if (pdev
->hdmi_hpd
) {
1109 if (blank
&& !pdev
->externalDisplay
->mBlanked
) {
1110 pdev
->externalDisplay
->disable();
1112 pdev
->externalDisplay
->mBlanked
= !!blank
;
1115 pdev
->primaryDisplay
->mBlanked
= !!blank
;
1117 /* Check if the thread is enabled before calling pthread_kill as we will seg fault otherwise */
1118 if(pdev
->update_stat_thread_flag
== true) {
1119 if (pthread_kill(pdev
->update_stat_thread
, 0) != ESRCH
) { //check if the thread is alive
1120 if (fb_blank
== FB_BLANK_POWERDOWN
) {
1121 pdev
->update_stat_thread_flag
= false;
1122 pthread_join(pdev
->update_stat_thread
, 0);
1125 } else { // thread is not alive
1126 if (fb_blank
== FB_BLANK_UNBLANK
&& pdev
->hwc_ctrl
.dynamic_recomp_mode
== true)
1127 exynos5_create_update_stat_thread(pdev
);
1129 #if defined(USES_DUAL_DISPLAY)
1130 struct decon_dual_display_blank_data blank_data
;
1131 memset(&blank_data
, 0, sizeof(blank_data
));
1132 blank_data
.display_type
= blank_data
.DECON_PRIMARY_DISPLAY
;
1133 blank_data
.blank
= fb_blank
;
1134 int err
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, S3CFB_DUAL_DISPLAY_BLANK
, &blank_data
);
1136 int err
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, FBIOBLANK
, fb_blank
);
1140 ALOGI("%sblank ioctl failed (display already %sblanked)",
1141 blank
? "" : "un", blank
? "" : "un");
1143 ALOGE("%sblank ioctl failed: %s", blank
? "" : "un",
1149 #if defined(USES_DUAL_DISPLAY)
1150 case HWC_DISPLAY_PRIMARY1
: {
1151 if (fb_blank
== FB_BLANK_POWERDOWN
) {
1153 if (pdev
->primaryDisplay
->mBlanked
)
1154 fence
= pdev
->primaryDisplay
->clearDisplay();
1156 HLOGE("error clearing primary display");
1161 /* To do: Should be implemented */
1162 pdev
->secondaryDisplay
->mBlanked
= !!blank
;
1163 struct decon_dual_display_blank_data blank_data
;
1164 memset(&blank_data
, 0, sizeof(blank_data
));
1165 blank_data
.display_type
= blank_data
.DECON_SECONDARY_DISPLAY
;
1166 blank_data
.blank
= fb_blank
;
1167 int err
= ioctl(pdev
->primaryDisplay
->mDisplayFd
, S3CFB_DUAL_DISPLAY_BLANK
, &blank_data
);
1171 case HWC_DISPLAY_EXTERNAL
:
1172 #if !defined(HDMI_ON_IN_SUSPEND) && !defined(CHANGE_POWEROFF_SEQ)
1173 if (pdev
->hdmi_hpd
) {
1174 if (blank
&& !pdev
->externalDisplay
->mBlanked
) {
1175 pdev
->externalDisplay
->disable();
1177 pdev
->externalDisplay
->mBlanked
= !!blank
;
1180 fence
= pdev
->externalDisplay
->clearDisplay();
1183 pdev
->externalDisplay
->mBlanked
= !!blank
;
1195 int exynos5_close(hw_device_t
* device
);
1197 int exynos5_open(const struct hw_module_t
*module
, const char *name
,
1198 struct hw_device_t
**device
)
1203 if (strcmp(name
, HWC_HARDWARE_COMPOSER
)) {
1207 struct exynos5_hwc_composer_device_1_t
*dev
;
1208 dev
= (struct exynos5_hwc_composer_device_1_t
*)malloc(sizeof(*dev
));
1209 memset(dev
, 0, sizeof(*dev
));
1211 dev
->primaryDisplay
= new ExynosPrimaryDisplay(NUM_GSC_UNITS
, dev
);
1212 dev
->externalDisplay
= new ExynosExternalDisplayModule(dev
);
1213 #ifdef USES_VIRTUAL_DISPLAY
1214 dev
->virtualDisplay
= new ExynosVirtualDisplayModule(dev
);
1216 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID
,
1217 (const struct hw_module_t
**)&dev
->primaryDisplay
->mGrallocModule
)) {
1218 ALOGE("failed to get gralloc hw module");
1220 goto err_get_module
;
1223 if (gralloc_open((const hw_module_t
*)dev
->primaryDisplay
->mGrallocModule
,
1224 &dev
->primaryDisplay
->mAllocDevice
)) {
1225 ALOGE("failed to open gralloc");
1227 goto err_get_module
;
1229 dev
->externalDisplay
->mAllocDevice
= dev
->primaryDisplay
->mAllocDevice
;
1230 #ifdef USES_VIRTUAL_DISPLAY
1231 dev
->virtualDisplay
->mAllocDevice
= dev
->primaryDisplay
->mAllocDevice
;
1234 dev
->primaryDisplay
->mDisplayFd
= open("/dev/graphics/fb0", O_RDWR
);
1235 if (dev
->primaryDisplay
->mDisplayFd
< 0) {
1236 ALOGE("failed to open framebuffer");
1237 ret
= dev
->primaryDisplay
->mDisplayFd
;
1241 struct fb_var_screeninfo info
;
1242 if (ioctl(dev
->primaryDisplay
->mDisplayFd
, FBIOGET_VSCREENINFO
, &info
) == -1) {
1243 ALOGE("FBIOGET_VSCREENINFO ioctl failed: %s", strerror(errno
));
1248 if (info
.reserved
[0] == 0 && info
.reserved
[1] == 0) {
1249 /* save physical lcd width, height to reserved[] */
1250 info
.reserved
[0] = info
.xres
;
1251 info
.reserved
[1] = info
.yres
;
1253 if (ioctl(dev
->primaryDisplay
->mDisplayFd
, FBIOPUT_VSCREENINFO
, &info
) == -1) {
1254 ALOGE("FBIOPUT_VSCREENINFO ioctl failed: %s", strerror(errno
));
1260 char value
[PROPERTY_VALUE_MAX
];
1261 property_get("debug.hwc.force_gpu", value
, "0");
1262 dev
->force_gpu
= atoi(value
);
1264 /* restore physical lcd width, height from reserved[] */
1265 int lcd_xres
, lcd_yres
;
1266 lcd_xres
= info
.reserved
[0];
1267 lcd_yres
= info
.reserved
[1];
1269 refreshRate
= 1000000000000LLU /
1271 uint64_t( info
.upper_margin
+ info
.lower_margin
+ lcd_yres
+ info
.vsync_len
)
1272 * ( info
.left_margin
+ info
.right_margin
+ lcd_xres
+ info
.hsync_len
)
1276 if (refreshRate
== 0) {
1277 ALOGW("invalid refresh rate, assuming 60 Hz");
1281 #if defined(USES_DUAL_DISPLAY)
1282 dev
->primaryDisplay
->mXres
= 2 * lcd_xres
;
1284 dev
->primaryDisplay
->mXres
= lcd_xres
;
1286 dev
->primaryDisplay
->mYres
= lcd_yres
;
1287 dev
->primaryDisplay
->mXdpi
= 1000 * (lcd_xres
* 25.4f
) / info
.width
;
1288 dev
->primaryDisplay
->mYdpi
= 1000 * (lcd_yres
* 25.4f
) / info
.height
;
1289 dev
->primaryDisplay
->mVsyncPeriod
= 1000000000 / refreshRate
;
1294 "width = %d mm (%f dpi)\n"
1295 "height = %d mm (%f dpi)\n"
1296 "refresh rate = %d Hz\n",
1297 dev
->primaryDisplay
->mXres
, dev
->primaryDisplay
->mYres
, info
.width
, dev
->primaryDisplay
->mXdpi
/ 1000.0,
1298 info
.height
, dev
->primaryDisplay
->mYdpi
/ 1000.0, refreshRate
);
1300 #ifdef FIMD_BW_OVERLAP_CHECK
1301 fimd_bw_overlap_limits_init(dev
->primaryDisplay
->mXres
, dev
->primaryDisplay
->mYres
,
1302 dev
->primaryDisplay
->mDmaChannelMaxBandwidth
, dev
->primaryDisplay
->mDmaChannelMaxOverlapCount
);
1304 for (size_t i
= 0; i
< MAX_NUM_FIMD_DMA_CH
; i
++) {
1305 dev
->primaryDisplay
->mDmaChannelMaxBandwidth
[i
] =2560 * 1600;
1306 dev
->primaryDisplay
->mDmaChannelMaxOverlapCount
[i
] = 1;
1311 #ifdef FIMD_WINDOW_OVERLAP_CHECK
1313 * Trivial implementation.
1314 * Effective only for checking the case that
1315 * mMaxWindowOverlapCnt = (NUM_HW_WINDOWS - 1)
1317 dev
->primaryDisplay
->mMaxWindowOverlapCnt
=
1318 fimd_window_overlap_limits_init(dev
->primaryDisplay
->mXres
, dev
->primaryDisplay
->mYres
);
1320 dev
->primaryDisplay
->mMaxWindowOverlapCnt
= NUM_HW_WINDOWS
;
1323 if (dev
->externalDisplay
->openHdmi() < 0) {
1324 ALOGE("openHdmi fail");
1327 #if defined(USES_DUAL_DISPLAY)
1328 dev
->secondaryDisplay
= new ExynosSecondaryDisplayModule(dev
);
1329 dev
->secondaryDisplay
->mAllocDevice
= dev
->primaryDisplay
->mAllocDevice
;
1332 dev
->mDisplayResourceManager
= new ExynosDisplayResourceManagerModule(dev
);
1334 char devname
[MAX_DEV_NAME
+ 1];
1335 devname
[MAX_DEV_NAME
] = '\0';
1337 strncpy(devname
, VSYNC_DEV_PREFIX
, MAX_DEV_NAME
);
1338 strlcat(devname
, VSYNC_DEV_NAME
, MAX_DEV_NAME
);
1340 dev
->vsync_fd
= open(devname
, O_RDONLY
);
1341 if (dev
->vsync_fd
< 0) {
1342 ALOGI("Failed to open vsync attribute at %s", devname
);
1343 devname
[strlen(VSYNC_DEV_PREFIX
)] = '\0';
1344 strlcat(devname
, VSYNC_DEV_MIDDLE
, MAX_DEV_NAME
);
1345 strlcat(devname
, VSYNC_DEV_NAME
, MAX_DEV_NAME
);
1346 ALOGI("Retrying with %s", devname
);
1347 dev
->vsync_fd
= open(devname
, O_RDONLY
);
1350 #ifdef TRY_SECOND_VSYNC_DEV
1351 if (dev
->vsync_fd
< 0) {
1352 strncpy(devname
, VSYNC_DEV_PREFIX
, MAX_DEV_NAME
);
1353 strlcat(devname
, VSYNC_DEV_NAME2
, MAX_DEV_NAME
);
1355 dev
->vsync_fd
= open(devname
, O_RDONLY
);
1356 if (dev
->vsync_fd
< 0) {
1357 ALOGI("Failed to open vsync attribute at %s", devname
);
1358 devname
[strlen(VSYNC_DEV_PREFIX
)] = '\0';
1359 strlcat(devname
, VSYNC_DEV_MIDDLE2
, MAX_DEV_NAME
);
1360 strlcat(devname
, VSYNC_DEV_NAME2
, MAX_DEV_NAME
);
1361 ALOGI("Retrying with %s", devname
);
1362 dev
->vsync_fd
= open(devname
, O_RDONLY
);
1368 if (dev
->vsync_fd
< 0) {
1369 ALOGE("failed to open vsync attribute");
1370 ret
= dev
->vsync_fd
;
1374 if (fstat(dev
->vsync_fd
, &st
) < 0) {
1375 ALOGE("Failed to stat vsync node at %s", devname
);
1376 goto err_vsync_stat
;
1379 if (!S_ISREG(st
.st_mode
)) {
1380 ALOGE("vsync node at %s should be a regualar file", devname
);
1381 goto err_vsync_stat
;
1385 dev
->psrInfoFd
= NULL
;
1387 char psrDevname
[MAX_DEV_NAME
+ 1];
1388 memset(psrDevname
, 0, MAX_DEV_NAME
+ 1);
1389 strncpy(psrDevname
, devname
, strlen(devname
) - 5);
1390 strlcat(psrDevname
, "psr_info", MAX_DEV_NAME
);
1391 ALOGI("PSR info devname = %s\n", psrDevname
);
1393 dev
->psrInfoFd
= fopen(psrDevname
, "r");
1394 if (dev
->psrInfoFd
== NULL
) {
1395 ALOGW("HWC needs to know whether LCD driver is using PSR mode or not\n");
1398 if (fread(&val
, 1, 1, dev
->psrInfoFd
) == 1) {
1399 dev
->psrMode
= (0x03 & atoi(val
));
1400 dev
->panelType
= ((0x03 << 2) & atoi(val
)) >> 2;
1404 ALOGI("PSR mode = %d (0: video mode, 1: DP PSR mode, 2: MIPI-DSI command mode)\n",
1406 ALOGI("Panel type = %d (0: Legacy, 1: DSC)\n",
1410 dev
->primaryDisplay
->mPanelType
= dev
->panelType
;
1411 if (dev
->panelType
== PANEL_DSC
) {
1412 uint32_t sliceNum
= 0;
1413 uint32_t sliceSize
= 0;
1414 if (fscanf(dev
->psrInfoFd
, "\n%d\n%d\n", &sliceNum
, &sliceSize
) < 0) {
1415 ALOGE("Fail to read slice information");
1417 dev
->primaryDisplay
->mDSCHSliceNum
= sliceNum
;
1418 dev
->primaryDisplay
->mDSCYSliceSize
= sliceSize
;
1420 ALOGI("DSC H_Slice_Num: %d, Y_Slice_Size: %d", dev
->primaryDisplay
->mDSCHSliceNum
, dev
->primaryDisplay
->mDSCYSliceSize
);
1424 dev
->base
.common
.tag
= HARDWARE_DEVICE_TAG
;
1425 dev
->base
.common
.version
= HWC_VERSION
;
1426 dev
->base
.common
.module
= const_cast<hw_module_t
*>(module
);
1427 dev
->base
.common
.close
= exynos5_close
;
1429 dev
->base
.prepare
= exynos5_prepare
;
1430 dev
->base
.set
= exynos5_set
;
1431 dev
->base
.eventControl
= exynos5_eventControl
;
1432 dev
->base
.query
= exynos5_query
;
1433 dev
->base
.registerProcs
= exynos5_registerProcs
;
1434 dev
->base
.dump
= exynos5_dump
;
1435 dev
->base
.getDisplayConfigs
= exynos5_getDisplayConfigs
;
1436 dev
->base
.getDisplayAttributes
= exynos5_getDisplayAttributes
;
1437 if (hwcHasApiVersion((hwc_composer_device_1_t
*)dev
, HWC_DEVICE_API_VERSION_1_4
)) {
1438 dev
->base
.getActiveConfig
= exynos_getActiveConfig
;
1439 dev
->base
.setActiveConfig
= exynos_setActiveConfig
;
1440 dev
->base
.setCursorPositionAsync
= exynos_setCursorPositionAsync
;
1441 dev
->base
.setPowerMode
= exynos_setPowerMode
;
1443 dev
->base
.blank
= exynos5_blank
;
1446 *device
= &dev
->base
.common
;
1449 android::ExynosIPService
*mIPService
;
1450 mIPService
= android::ExynosIPService::getExynosIPService();
1451 ret
= mIPService
->createServiceLocked();
1457 android::ExynosHWCService
*mHWCService
;
1458 mHWCService
= android::ExynosHWCService::getExynosHWCService();
1459 mHWCService
->setExynosHWCCtx(dev
);
1460 mHWCService
->setPSRExitCallback(doPSRExit
);
1461 #if !defined(HDMI_INCAPABLE)
1462 mHWCService
->setBootFinishedCallback(exynos5_boot_finished
);
1466 dev
->mHdmiResolutionChanged
= false;
1467 dev
->mHdmiResolutionHandled
= true;
1468 dev
->mS3DMode
= S3D_MODE_DISABLED
;
1469 dev
->mHdmiPreset
= HDMI_PRESET_DEFAULT
;
1470 dev
->mHdmiCurrentPreset
= HDMI_PRESET_DEFAULT
;
1471 dev
->mUseSubtitles
= false;
1472 dev
->notifyPSRExit
= false;
1474 #if defined(USES_CEC)
1481 ret
= pthread_create(&dev
->vsync_thread
, NULL
, hwc_vsync_thread
, dev
);
1483 ALOGE("failed to start vsync thread: %s", strerror(ret
));
1488 #ifdef G2D_COMPOSITION
1489 dev
->primaryDisplay
->num_of_allocated_lay
= 0;
1492 dev
->allowOTF
= true;
1494 dev
->hwc_ctrl
.max_num_ovly
= NUM_HW_WINDOWS
;
1495 dev
->hwc_ctrl
.num_of_video_ovly
= 2;
1496 dev
->hwc_ctrl
.dynamic_recomp_mode
= (dev
->psrMode
== PSR_NONE
);
1497 dev
->hwc_ctrl
.skip_static_layer_mode
= true;
1498 dev
->hwc_ctrl
.dma_bw_balance_mode
= true;
1502 if (dev
->hwc_ctrl
.dynamic_recomp_mode
== true)
1503 exynos5_create_update_stat_thread(dev
);
1508 if (dev
->psrInfoFd
!= NULL
)
1509 fclose(dev
->psrInfoFd
);
1511 close(dev
->vsync_fd
);
1513 if (dev
->externalDisplay
->mDisplayFd
> 0)
1514 close(dev
->externalDisplay
->mDisplayFd
);
1516 close(dev
->primaryDisplay
->mDisplayFd
);
1517 #if defined(USES_DUAL_DISPLAY)
1518 if (dev
->secondaryDisplay
->mDisplayFd
> 0)
1519 close(dev
->secondaryDisplay
->mDisplayFd
);
1522 gralloc_close(dev
->primaryDisplay
->mAllocDevice
);
1528 int exynos5_close(hw_device_t
*device
)
1530 struct exynos5_hwc_composer_device_1_t
*dev
=
1531 (struct exynos5_hwc_composer_device_1_t
*)device
;
1532 pthread_kill(dev
->vsync_thread
, SIGTERM
);
1533 pthread_join(dev
->vsync_thread
, NULL
);
1534 if (pthread_kill(dev
->update_stat_thread
, 0) != ESRCH
) {
1535 pthread_kill(dev
->update_stat_thread
, SIGTERM
);
1536 pthread_join(dev
->update_stat_thread
, NULL
);
1539 for (size_t i
= 0; i
< NUM_GSC_UNITS
; i
++)
1540 dev
->primaryDisplay
->mMPPs
[i
]->cleanupM2M();
1542 gralloc_close(dev
->primaryDisplay
->mAllocDevice
);
1543 close(dev
->vsync_fd
);
1545 #ifdef USE_FB_PHY_LINEAR
1546 #ifdef G2D_COMPOSITION
1547 for (int i
= 0; i
< NUM_HW_WIN_FB_PHY
; i
++) {
1548 for (int j
= 0; j
< NUM_GSC_DST_BUFS
; j
++) {
1549 if (dev
->win_buf_vir_addr
[i
][j
]) {
1550 ion_unmap((void *)dev
->win_buf_vir_addr
[i
][j
], dev
->win_buf_map_size
[i
]);
1551 dev
->win_buf_vir_addr
[i
][j
] = 0;
1557 for (int i
= 0; i
< NUM_HW_WIN_FB_PHY
; i
++) {
1558 for (int j
= 0; j
< NUM_GSC_DST_BUFS
; j
++) {
1559 if (dev
->win_buf
[i
][j
]) {
1560 dev
->primaryDisplay
->mAllocDevice
->free(dev
->primaryDisplay
->mAllocDevice
, dev
->win_buf
[i
][j
]);
1561 dev
->win_buf
[i
][j
] = NULL
;
1568 delete dev
->mDisplayResourceManager
;
1574 static struct hw_module_methods_t exynos5_hwc_module_methods
= {
1575 .open
= exynos5_open
,
1578 hwc_module_t HAL_MODULE_INFO_SYM
= {
1580 .tag
= HARDWARE_MODULE_TAG
,
1581 .module_api_version
= HWC_MODULE_API_VERSION_0_1
,
1582 .hal_api_version
= HARDWARE_HAL_API_VERSION
,
1583 .id
= HWC_HARDWARE_MODULE_ID
,
1584 .name
= "Samsung exynos5 hwcomposer module",
1585 .author
= "Samsung LSI",
1586 .methods
= &exynos5_hwc_module_methods
,