libhwc: resolve compilation errors
[GitHub/LineageOS/android_hardware_samsung_slsi_exynos.git] / libhwc / ExynosHWC.cpp
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 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <utils/Trace.h>
22
23 #if defined(USES_CEC)
24 #include "libcec.h"
25 #endif
26
27 #ifdef HWC_SERVICES
28 #include "ExynosHWCService.h"
29 namespace android {
30 class ExynosHWCService;
31 }
32 #endif
33
34 #ifdef IP_SERVICE
35 #include "ExynosIPService.h"
36 #endif
37
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"
46 #endif
47 #ifdef USES_VIRTUAL_DISPLAY
48 #include "ExynosVirtualDisplayModule.h"
49 #endif
50
51 void doPSRExit(struct exynos5_hwc_composer_device_1_t *pdev)
52 {
53 int val;
54 int ret;
55 if (pdev->psrMode != PSR_NONE && pdev->notifyPSRExit) {
56 pdev->notifyPSRExit = false;
57 ret = ioctl(pdev->primaryDisplay->mDisplayFd, S3CFB_WIN_PSR_EXIT, &val);
58 }
59 }
60
61 #if defined(USES_CEC)
62 void handle_cec(exynos5_hwc_composer_device_1_t *pdev)
63 {
64 unsigned char buffer[16];
65 int size;
66 unsigned char lsrc, ldst, opcode;
67
68 size = CECReceiveMessage(buffer, CEC_MAX_FRAME_SIZE, 1000);
69
70 /* no data available or ctrl-c */
71 if (!size)
72 return;
73
74 /* "Polling Message" */
75 if (size == 1)
76 return;
77
78 lsrc = buffer[0] >> 4;
79
80 /* ignore messages with src address == mCecLaddr */
81 if (lsrc == pdev->mCecLaddr)
82 return;
83
84 opcode = buffer[1];
85
86 if (CECIgnoreMessage(opcode, lsrc)) {
87 ALOGE("### ignore message coming from address 15 (unregistered)");
88 return;
89 }
90
91 if (!CECCheckMessageSize(opcode, size)) {
92 /*
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
96 * the correct size
97 */
98 ALOGD("### invalid message size: %d(opcode: 0x%x) ###", size, opcode);
99 }
100
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) ###");
104 return;
105 }
106
107 ldst = lsrc;
108
109 /* TODO: macros to extract src and dst logical addresses */
110 /* TODO: macros to extract opcode */
111
112 switch (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;
119 buffer[4] = 3;
120 size = 5;
121 break;
122
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;
130 size = 4;
131 break;
132
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;
137 buffer[2] = 0;
138 size = 3;
139 break;
140
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;
145 buffer[2] = 0x6D;
146 size = 3;
147 break;
148
149 case CEC_OPCODE_USER_CONTROL_PRESSED:
150 buffer[0] = (pdev->mCecLaddr << 4) | ldst;
151 size = 1;
152 break;
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;
157 buffer[2] = 0x11;
158 size = 3;
159 break;
160
161 case CEC_OPCODE_ABORT:
162 case CEC_OPCODE_FEATURE_ABORT:
163 default:
164 /* send "Feature Abort" */
165 buffer[0] = (pdev->mCecLaddr << 4) | ldst;
166 buffer[1] = CEC_OPCODE_FEATURE_ABORT;
167 buffer[2] = CEC_OPCODE_ABORT;
168 buffer[3] = 0x04;
169 size = 4;
170 break;
171 }
172
173 if (CECSendMessage(buffer, size) != size)
174 ALOGE("CECSendMessage() failed!!!");
175 }
176
177 void start_cec(exynos5_hwc_composer_device_1_t *pdev)
178 {
179 unsigned char buffer[CEC_MAX_FRAME_SIZE];
180 int 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");
186 return;
187 }
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;
192 size = 2;
193 if (CECSendMessage(buffer, size) != size)
194 ALOGE("CECSendMessage(%#x) failed!!!", buffer[0]);
195 }
196 #endif
197
198 void exynos5_boot_finished(exynos5_hwc_composer_device_1_t *dev)
199 {
200 ALOGD("Boot Finished");
201 int sw_fd;
202 exynos5_hwc_composer_device_1_t *pdev =
203 (exynos5_hwc_composer_device_1_t *)dev;
204 if (pdev == NULL) {
205 ALOGE("%s:: dev is NULL", __func__);
206 return;
207 }
208 sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY);
209
210 if (sw_fd >= 0) {
211 char val;
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;
218 }
219 pdev->externalDisplay->mBlanked = false;
220 #if defined(USES_CEC)
221 start_cec(pdev);
222 #endif
223 if (pdev->procs) {
224 pdev->procs->hotplug(pdev->procs, HWC_DISPLAY_EXTERNAL, true);
225 pdev->procs->invalidate(pdev->procs);
226 }
227 }
228 }
229 close(sw_fd);
230 }
231 }
232
233 int exynos5_prepare(hwc_composer_device_1_t *dev,
234 size_t numDisplays, hwc_display_contents_1_t** displays)
235 {
236 ATRACE_CALL();
237 if (!numDisplays || !displays)
238 return 0;
239
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];
245 #else
246 hwc_display_contents_1_t *fimd_contents = displays[HWC_DISPLAY_PRIMARY];
247 #endif
248
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);
257 #endif
258 #endif
259 pdev->updateCallCnt++;
260 pdev->update_event_cnt++;
261 pdev->LastUpdateTimeStamp = systemTime(SYSTEM_TIME_MONOTONIC);
262 pdev->primaryDisplay->getCompModeSwitch();
263 pdev->totPixels = 0;
264 pdev->incomingPixels = 0;
265
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();
271 }
272 #endif
273
274 pdev->externalDisplay->setHdmiStatus(pdev->hdmi_hpd);
275
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();
281 }
282 #endif
283
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);
288 }
289
290 #ifdef USES_VPP
291 pdev->mDisplayResourceManager->assignResources(numDisplays, displays);
292 #endif
293
294 if (fimd_contents) {
295 android::Mutex::Autolock lock(pdev->primaryDisplay->mLayerInfoMutex);
296 int err = pdev->primaryDisplay->prepare(fimd_contents);
297 if (err)
298 return err;
299 }
300 if (hdmi_contents) {
301 android::Mutex::Autolock lock(pdev->externalDisplay->mLayerInfoMutex);
302 int err = 0;
303 err = pdev->externalDisplay->prepare(hdmi_contents);
304 if (err)
305 return err;
306 }
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);
311 if (err)
312 return err;
313 }
314 #endif
315
316
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);
322 #endif
323 int err = pdev->virtualDisplay->prepare(virtual_contents);
324 if (err)
325 return err;
326 }
327 #endif
328
329 return 0;
330 }
331
332 int exynos5_set(struct hwc_composer_device_1 *dev,
333 size_t numDisplays, hwc_display_contents_1_t** displays)
334 {
335 ATRACE_CALL();
336 if (!numDisplays || !displays)
337 return 0;
338
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];
344 #else
345 hwc_display_contents_1_t *fimd_contents = displays[HWC_DISPLAY_PRIMARY];
346 #endif
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
350 int virtual_err = 0;
351 hwc_display_contents_1_t *virtual_contents = displays[HWC_DISPLAY_VIRTUAL];
352 #endif
353
354 #if defined(USES_DUAL_DISPLAY)
355 if ((pdev->hdmi_hpd == false) && fimd_contents1) {
356 hdmi_err = pdev->secondaryDisplay->set(fimd_contents1);
357 }
358 #endif
359
360 if (fimd_contents) {
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);
364 #else
365 fimd_err = pdev->primaryDisplay->set(fimd_contents);
366 #endif
367 }
368
369 if (pdev->mS3DMode != S3D_MODE_STOPPING && !pdev->mHdmiResolutionHandled) {
370 pdev->mHdmiResolutionHandled = true;
371 pdev->hdmi_hpd = true;
372 pdev->externalDisplay->enable();
373 if (pdev->procs) {
374 pdev->procs->hotplug(pdev->procs, HWC_DISPLAY_EXTERNAL, true);
375 pdev->procs->invalidate(pdev->procs);
376 }
377 }
378
379 if (hdmi_contents && fimd_contents) {
380 android::Mutex::Autolock lock(pdev->externalDisplay->mLayerInfoMutex);
381 hdmi_err = pdev->externalDisplay->set(hdmi_contents);
382 }
383
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);
387 }
388 if (pdev->mS3DMode == S3D_MODE_STOPPING) {
389 pdev->mS3DMode = S3D_MODE_DISABLED;
390 #ifndef USES_VPP
391 for (int i = 0; i < pdev->primaryDisplay->mNumMPPs; i++)
392 pdev->primaryDisplay->mMPPs[i]->mS3DMode = S3D_NONE;
393
394 if (pdev->externalDisplay->mMPPs[0] != NULL)
395 pdev->externalDisplay->mMPPs[0]->mS3DMode = S3D_NONE;
396 #endif
397 }
398
399 #ifdef USES_VIRTUAL_DISPLAY
400 if (virtual_contents && fimd_contents)
401 virtual_err = pdev->virtualDisplay->set(virtual_contents);
402 #endif
403
404 #ifdef EXYNOS_SUPPORT_PSR_EXIT
405 pdev->notifyPSRExit = true;
406 #else
407 pdev->notifyPSRExit = false;
408 #endif
409
410 pdev->primaryDisplay->freeMPP();
411
412 #ifdef USES_VPP
413 pdev->mDisplayResourceManager->cleanupMPPs();
414 #endif
415
416 if (fimd_err)
417 return fimd_err;
418
419 #ifndef USES_VIRTUAL_DISPLAY
420 return hdmi_err;
421 #else
422 if (hdmi_err)
423 return hdmi_err;
424
425 return virtual_err;
426 #endif
427 }
428
429 void exynos5_registerProcs(struct hwc_composer_device_1* dev,
430 hwc_procs_t const* procs)
431 {
432 struct exynos5_hwc_composer_device_1_t* pdev =
433 (struct exynos5_hwc_composer_device_1_t*)dev;
434 pdev->procs = procs;
435 }
436
437 int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value)
438 {
439 struct exynos5_hwc_composer_device_1_t *pdev =
440 (struct exynos5_hwc_composer_device_1_t *)dev;
441
442 switch (what) {
443 case HWC_BACKGROUND_LAYER_SUPPORTED:
444 // we do not support the background layer
445 value[0] = 0;
446 break;
447 case HWC_VSYNC_PERIOD:
448 // vsync period in nanosecond
449 value[0] = pdev->primaryDisplay->mVsyncPeriod;
450 break;
451 default:
452 // unsupported query
453 return -EINVAL;
454 }
455 return 0;
456 }
457
458 int exynos5_eventControl(struct hwc_composer_device_1 *dev, int __unused dpy,
459 int event, int enabled)
460 {
461 struct exynos5_hwc_composer_device_1_t *pdev =
462 (struct exynos5_hwc_composer_device_1_t *)dev;
463
464 switch (event) {
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);
469 if (err < 0) {
470 ALOGE("vsync ioctl failed");
471 return -errno;
472 }
473 return 0;
474 }
475
476 return -EINVAL;
477 }
478
479 void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev,
480 const char *buff, int len)
481 {
482 const char *s = buff;
483 s += strlen(s) + 1;
484
485 while (*s) {
486 if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
487 pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1;
488
489 s += strlen(s) + 1;
490 if (s - buff >= len)
491 break;
492 }
493
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;
498 return;
499 }
500
501 pdev->externalDisplay->mBlanked = false;
502 #if defined(USES_CEC)
503 start_cec(pdev);
504 } else {
505 CECClose();
506 pdev->mCecFd = -1;
507 }
508 #else
509 }
510 #endif
511
512 ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled");
513 if (pdev->hdmi_hpd)
514 ALOGI("HDMI Resolution changed to %dx%d",
515 pdev->externalDisplay->mXres, pdev->externalDisplay->mYres);
516
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. */
520 if (pdev->procs)
521 pdev->procs->hotplug(pdev->procs, HWC_DISPLAY_EXTERNAL, pdev->hdmi_hpd);
522 }
523
524 void handle_tui_uevent(struct exynos5_hwc_composer_device_1_t *pdev __unused,
525 const char *buff __unused, int len __unused)
526 {
527 #ifdef USES_VPP
528 #ifdef DISABLE_IDMA_SECURE
529 return;
530 #else
531 const char *s = buff;
532 unsigned int tui_disabled = 1;
533 bool useSecureDMA = true;
534 s += strlen(s) + 1;
535
536 while (*s) {
537 if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
538 tui_disabled = atoi(s + strlen("SWITCH_STATE=")) == 0;
539
540 s += strlen(s) + 1;
541 if (s - buff >= len)
542 break;
543 }
544
545 if (tui_disabled)
546 useSecureDMA = true;
547 else
548 useSecureDMA = false;
549
550 ALOGI("TUI mode is %s", tui_disabled ? "disabled" : "enabled");
551
552 if (pdev->primaryDisplay->mUseSecureDMA != useSecureDMA) {
553 pdev->primaryDisplay->mUseSecureDMA = useSecureDMA;
554 if ((pdev->procs) && (pdev->procs->invalidate))
555 pdev->procs->invalidate(pdev->procs);
556 }
557 #endif
558 #endif
559 }
560
561 void handle_vsync_event(struct exynos5_hwc_composer_device_1_t *pdev)
562 {
563 if (!pdev->procs)
564 return;
565
566 int err = lseek(pdev->vsync_fd, 0, SEEK_SET);
567 if (err < 0) {
568 ALOGE("error seeking to vsync timestamp: %s", strerror(errno));
569 return;
570 }
571
572 char buf[4096];
573 err = read(pdev->vsync_fd, buf, sizeof(buf));
574 if (err < 0) {
575 ALOGE("error reading vsync timestamp: %s", strerror(errno));
576 return;
577 }
578 buf[sizeof(buf) - 1] = '\0';
579
580 errno = 0;
581 uint64_t timestamp = strtoull(buf, NULL, 0);
582 if (!errno)
583 pdev->procs->vsync(pdev->procs, 0, timestamp);
584 }
585
586 void *hwc_update_stat_thread(void *data)
587 {
588 struct exynos5_hwc_composer_device_1_t *pdev =
589 (struct exynos5_hwc_composer_device_1_t *)data;
590 int event_cnt = 0;
591
592 while (pdev->update_stat_thread_flag) {
593 event_cnt = pdev->update_event_cnt;
594 /*
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.
597 */
598 usleep(100000);
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);
604 }
605 }
606 }
607 }
608 return NULL;
609 }
610
611 void exynos5_create_update_stat_thread(struct exynos5_hwc_composer_device_1_t *dev)
612 {
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;
617 } else {
618 dev->update_stat_thread_flag = true;
619 }
620 }
621
622 void *hwc_vsync_thread(void *data)
623 {
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));
628
629 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
630
631 uevent_init();
632
633 char temp[4096];
634 int err = read(pdev->vsync_fd, temp, sizeof(temp));
635 if (err < 0) {
636 ALOGE("error reading vsync timestamp: %s", strerror(errno));
637 return NULL;
638 }
639
640 #if defined(USES_CEC)
641 struct pollfd fds[3];
642 #else
643 struct pollfd fds[2];
644 #endif
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;
652 #endif
653
654 while (true) {
655 #if defined(USES_CEC)
656 int err;
657 fds[2].fd = pdev->mCecFd;
658 if (fds[2].fd > 0)
659 err = poll(fds, 3, -1);
660 else
661 err = poll(fds, 2, -1);
662 #else
663 int err = poll(fds, 2, -1);
664 #endif
665
666 if (err > 0) {
667 if (fds[0].revents & POLLPRI) {
668 handle_vsync_event(pdev);
669 }
670 else if (fds[1].revents & POLLIN) {
671 int len = uevent_next_event(uevent_desc,
672 sizeof(uevent_desc) - 2);
673
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");
678
679 if (hdmi)
680 handle_hdmi_uevent(pdev, uevent_desc, len);
681 else if (tui_status)
682 handle_tui_uevent(pdev, uevent_desc, len);
683 #if defined(USES_CEC)
684 } else if (pdev->hdmi_hpd && fds[2].revents & POLLIN) {
685 handle_cec(pdev);
686 #endif
687 }
688 }
689 else if (err == -1) {
690 if (errno == EINTR)
691 break;
692 ALOGE("error in vsync thread: %s", strerror(errno));
693 }
694 }
695
696 return NULL;
697 }
698
699 int exynos5_blank(struct hwc_composer_device_1 *dev, int disp, int blank)
700 {
701 ATRACE_CALL();
702 struct exynos5_hwc_composer_device_1_t *pdev =
703 (struct exynos5_hwc_composer_device_1_t *)dev;
704 #ifdef SKIP_DISPLAY_BLANK_CTRL
705 return 0;
706 #endif
707 ALOGI("%s:: disp(%d), blank(%d)", __func__, disp, blank);
708 switch (disp) {
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();
713 if (fence < 0) {
714 HLOGE("error clearing primary display");
715 } else {
716 #ifndef USES_VPP
717 if (pdev->primaryDisplay->mGscUsed && pdev->primaryDisplay->mMPPs[FIMD_GSC_IDX]->isOTF())
718 pdev->primaryDisplay->mMPPs[FIMD_GSC_IDX]->cleanupOTF();
719 #endif
720 close(fence);
721 }
722 }
723 #if !defined(HDMI_ON_IN_SUSPEND) && defined(CHANGE_POWEROFF_SEQ)
724 /*
725 * LCD power block shouldn't be turned off
726 * before TV power block is turned off in Exynos4.
727 */
728 if (pdev->hdmi_hpd) {
729 if (blank && !pdev->externalDisplay->mBlanked) {
730 pdev->externalDisplay->disable();
731 }
732 pdev->externalDisplay->mBlanked = !!blank;
733 }
734 #endif
735 pdev->primaryDisplay->mBlanked = !!blank;
736
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);
743 }
744 }
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);
748 }
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);
755 #else
756 int err = ioctl(pdev->primaryDisplay->mDisplayFd, FBIOBLANK, fb_blank);
757 #endif
758 if (err < 0) {
759 if (errno == EBUSY)
760 ALOGI("%sblank ioctl failed (display already %sblanked)",
761 blank ? "" : "un", blank ? "" : "un");
762 else
763 ALOGE("%sblank ioctl failed: %s", blank ? "" : "un",
764 strerror(errno));
765 return -errno;
766 }
767 break;
768 }
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);
779 break;
780 }
781 #endif
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();
787 }
788 pdev->externalDisplay->mBlanked = !!blank;
789 }
790 #else
791 fence = pdev->externalDisplay->clearDisplay();
792 if (fence >= 0)
793 close(fence);
794 pdev->externalDisplay->mBlanked = !!blank;
795 #endif
796 break;
797
798 default:
799 return -EINVAL;
800
801 }
802
803 return 0;
804 }
805
806 void exynos5_dump(hwc_composer_device_1* dev, char *buff, int buff_len)
807 {
808 if (buff_len <= 0)
809 return;
810
811 struct exynos5_hwc_composer_device_1_t *pdev =
812 (struct exynos5_hwc_composer_device_1_t *)dev;
813
814 android::String8 result;
815
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);
819
820 result.append("Primary device's config information\n");
821 pdev->primaryDisplay->dump(result);
822
823 #ifdef USES_VPP
824 if (pdev->hdmi_hpd) {
825 result.append("\n");
826 result.append("External device's config information\n");
827 pdev->externalDisplay->dump(result);
828 }
829 #if defined(USES_DUAL_DISPLAY)
830 else {
831 result.append("\n");
832 result.append("Secondary device's config information\n");
833 pdev->secondaryDisplay->dump(result);
834 }
835 #endif
836 #ifdef USES_VIRTUAL_DISPLAY_DECON_EXT_WB
837 if (pdev->virtualDisplay->mIsWFDState) {
838 result.append("\n");
839 result.append("Virtual device's config information\n");
840 pdev->virtualDisplay->dump(result);
841 }
842 #endif
843 #endif
844 {
845 android::Mutex::Autolock lock(pdev->primaryDisplay->mLayerInfoMutex);
846 result.append("\n");
847 result.append("Primary device's layer information\n");
848 pdev->primaryDisplay->dumpLayerInfo(result);
849 }
850
851 if (pdev->hdmi_hpd) {
852 android::Mutex::Autolock lock(pdev->externalDisplay->mLayerInfoMutex);
853 result.append("\n");
854 result.append("External device's layer information\n");
855 pdev->externalDisplay->dumpLayerInfo(result);
856 }
857 #if defined(USES_DUAL_DISPLAY)
858 else {
859 android::Mutex::Autolock lock(pdev->secondaryDisplay->mLayerInfoMutex);
860 result.append("\n");
861 result.append("Secondary device's layer information\n");
862 pdev->secondaryDisplay->dumpLayerInfo(result);
863 }
864 #endif
865 #if USES_VIRTUAL_DISPLAY_DECON_EXT_WB
866 if (pdev->virtualDisplay->mIsWFDState) {
867 android::Mutex::Autolock lock(pdev->virtualDisplay->mLayerInfoMutex);
868 result.append("\n");
869 result.append("Virtual device's layer information\n");
870 pdev->virtualDisplay->dumpLayerInfo(result);
871 }
872 #endif
873 strlcpy(buff, result.string(), buff_len);
874 }
875
876 int exynos5_getDisplayConfigs(struct hwc_composer_device_1 *dev,
877 int disp, uint32_t *configs, size_t *numConfigs)
878 {
879 struct exynos5_hwc_composer_device_1_t *pdev =
880 (struct exynos5_hwc_composer_device_1_t *)dev;
881 int err = 0;
882
883 if (*numConfigs == 0)
884 return 0;
885
886 #if defined(USES_DUAL_DISPLAY)
887 if (disp == HWC_DISPLAY_PRIMARY0) {
888 configs[0] = 0;
889 *numConfigs = 1;
890 return 0;
891 } else if (disp == HWC_DISPLAY_PRIMARY1) {
892 configs[0] = 0;
893 *numConfigs = 1;
894 return 0;
895 #else
896 if (disp == HWC_DISPLAY_PRIMARY) {
897 configs[0] = 0;
898 *numConfigs = 1;
899 return 0;
900 #endif
901 } else if (disp == HWC_DISPLAY_EXTERNAL) {
902 if (!pdev->hdmi_hpd) {
903 return -EINVAL;
904 }
905 if (hwcHasApiVersion((hwc_composer_device_1_t*)dev, HWC_DEVICE_API_VERSION_1_4))
906 err = pdev->externalDisplay->getDisplayConfigs(configs, numConfigs);
907 else {
908 err = pdev->externalDisplay->getConfig();
909 configs[0] = 0;
910 *numConfigs = 1;
911 }
912 if (err) {
913 return -EINVAL;
914 }
915 return 0;
916 #ifdef USES_VIRTUAL_DISPLAY
917 } else if (disp == HWC_DISPLAY_VIRTUAL) {
918 int err = pdev->virtualDisplay->getConfig();
919 if (err) {
920 return -EINVAL;
921 }
922 configs[0] = 0;
923 *numConfigs = 1;
924 return 0;
925 #endif
926 }
927
928 return -EINVAL;
929 }
930
931 int32_t exynos5_hdmi_attribute(struct exynos5_hwc_composer_device_1_t *pdev,
932 const uint32_t attribute)
933 {
934 switch(attribute) {
935 case HWC_DISPLAY_VSYNC_PERIOD:
936 return pdev->primaryDisplay->mVsyncPeriod;
937
938 case HWC_DISPLAY_WIDTH:
939 return pdev->externalDisplay->mXres;
940
941 case HWC_DISPLAY_HEIGHT:
942 return pdev->externalDisplay->mYres;
943
944 case HWC_DISPLAY_DPI_X:
945 case HWC_DISPLAY_DPI_Y:
946 return 0; // unknown
947
948 default:
949 ALOGE("unknown display attribute %u", attribute);
950 return -EINVAL;
951 }
952 }
953
954 int exynos5_getDisplayAttributes(struct hwc_composer_device_1 *dev,
955 int disp, uint32_t config, const uint32_t *attributes, int32_t *values)
956 {
957 struct exynos5_hwc_composer_device_1_t *pdev =
958 (struct exynos5_hwc_composer_device_1_t *)dev;
959
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]);
966 #else
967 if (disp == HWC_DISPLAY_PRIMARY)
968 values[i] = pdev->primaryDisplay->getDisplayAttributes(attributes[i], config);
969 #endif
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);
973 else
974 values[i] = exynos5_hdmi_attribute(pdev, attributes[i]);
975 }
976 #ifdef USES_VIRTUAL_DISPLAY
977 else if (disp == HWC_DISPLAY_VIRTUAL)
978 values[i] = pdev->virtualDisplay->getDisplayAttributes(attributes[i]);
979 #endif
980 else {
981 ALOGE("unknown display type %u", disp);
982 return -EINVAL;
983 }
984 }
985
986 return 0;
987 }
988
989 int exynos_getActiveConfig(struct hwc_composer_device_1* dev, int disp)
990 {
991 struct exynos5_hwc_composer_device_1_t *pdev =
992 (struct exynos5_hwc_composer_device_1_t *)dev;
993 if (disp == HWC_DISPLAY_PRIMARY)
994 return 0;
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();
999 else
1000 return 0;
1001 } else {
1002 ALOGE("%s::External device is not connected", __func__);
1003 return -1;
1004 }
1005 } else if (disp == HWC_DISPLAY_VIRTUAL)
1006 return 0;
1007 else {
1008 ALOGE("%s:: unknown display type %u", __func__, disp);
1009 return -EINVAL;
1010 }
1011 }
1012
1013 int exynos_setActiveConfig(struct hwc_composer_device_1* dev, int disp, int index)
1014 {
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) {
1019 if (index != 0) {
1020 ALOGE("%s::Primary display doen't support index(%d)", __func__, index);
1021 return -1;
1022 }
1023 return 0;
1024 }
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);
1029 } else {
1030 if (index != 0) {
1031 ALOGE("%s::External display doen't support index(%d)", __func__, index);
1032 return -1;
1033 } else {
1034 return 0;
1035 }
1036 }
1037 } else {
1038 ALOGE("%s::External device is not connected", __func__);
1039 return -1;
1040 }
1041 } else if (disp == HWC_DISPLAY_VIRTUAL)
1042 return 0;
1043
1044 return -1;
1045 }
1046
1047 int exynos_setCursorPositionAsync(struct hwc_composer_device_1 *dev __unused, int disp __unused, int x_pos __unused, int y_pos __unused)
1048 {
1049 return 0;
1050 }
1051
1052 int exynos_setPowerMode(struct hwc_composer_device_1* dev, int disp, int mode)
1053 {
1054 ATRACE_CALL();
1055 struct exynos5_hwc_composer_device_1_t *pdev =
1056 (struct exynos5_hwc_composer_device_1_t *)dev;
1057 #ifdef SKIP_DISPLAY_BLANK_CTRL
1058 return 0;
1059 #endif
1060 ALOGI("%s:: disp(%d), mode(%d)", __func__, disp, mode);
1061 int fb_blank = 0;
1062 int blank = 0;
1063 if (mode == HWC_POWER_MODE_OFF) {
1064 fb_blank = FB_BLANK_POWERDOWN;
1065 blank = 1;
1066 } else {
1067 fb_blank = FB_BLANK_UNBLANK;
1068 blank = 0;
1069 }
1070
1071 switch (disp) {
1072 case HWC_DISPLAY_PRIMARY: {
1073 #ifdef USES_VPP
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);
1078 if (err < 0) {
1079 ALOGE("blank ioctl failed: %s, mode(%d)", strerror(errno), mode);
1080 return -errno;
1081 }
1082 }
1083 pdev->primaryDisplay->mBlanked = 0;
1084 return pdev->primaryDisplay->setPowerMode(mode);
1085 }
1086 #endif
1087 if (fb_blank == FB_BLANK_POWERDOWN) {
1088 int fence = -1;
1089 #if defined(USES_DUAL_DISPLAY)
1090 if (pdev->secondaryDisplay->mBlanked)
1091 #endif
1092 fence = pdev->primaryDisplay->clearDisplay();
1093 if (fence < 0) {
1094 HLOGE("error clearing primary display");
1095 } else {
1096 #ifndef USES_VPP
1097 if (pdev->primaryDisplay->mGscUsed && pdev->primaryDisplay->mMPPs[FIMD_GSC_IDX]->isOTF())
1098 pdev->primaryDisplay->mMPPs[FIMD_GSC_IDX]->cleanupOTF();
1099 #endif
1100 close(fence);
1101 }
1102 }
1103 #if !defined(HDMI_ON_IN_SUSPEND) && defined(CHANGE_POWEROFF_SEQ)
1104 /*
1105 * LCD power block shouldn't be turned off
1106 * before TV power block is turned off in Exynos4.
1107 */
1108 if (pdev->hdmi_hpd) {
1109 if (blank && !pdev->externalDisplay->mBlanked) {
1110 pdev->externalDisplay->disable();
1111 }
1112 pdev->externalDisplay->mBlanked = !!blank;
1113 }
1114 #endif
1115 pdev->primaryDisplay->mBlanked = !!blank;
1116
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);
1123 }
1124 }
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);
1128 }
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);
1135 #else
1136 int err = ioctl(pdev->primaryDisplay->mDisplayFd, FBIOBLANK, fb_blank);
1137 #endif
1138 if (err < 0) {
1139 if (errno == EBUSY)
1140 ALOGI("%sblank ioctl failed (display already %sblanked)",
1141 blank ? "" : "un", blank ? "" : "un");
1142 else
1143 ALOGE("%sblank ioctl failed: %s", blank ? "" : "un",
1144 strerror(errno));
1145 return -errno;
1146 }
1147 break;
1148 }
1149 #if defined(USES_DUAL_DISPLAY)
1150 case HWC_DISPLAY_PRIMARY1: {
1151 if (fb_blank == FB_BLANK_POWERDOWN) {
1152 int fence = -1;
1153 if (pdev->primaryDisplay->mBlanked)
1154 fence = pdev->primaryDisplay->clearDisplay();
1155 if (fence < 0) {
1156 HLOGE("error clearing primary display");
1157 } else {
1158 close(fence);
1159 }
1160 }
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);
1168 break;
1169 }
1170 #endif
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();
1176 }
1177 pdev->externalDisplay->mBlanked = !!blank;
1178 }
1179 #else
1180 fence = pdev->externalDisplay->clearDisplay();
1181 if (fence >= 0)
1182 close(fence);
1183 pdev->externalDisplay->mBlanked = !!blank;
1184 #endif
1185 break;
1186
1187 default:
1188 return -EINVAL;
1189
1190 }
1191
1192 return 0;
1193 }
1194
1195 int exynos5_close(hw_device_t* device);
1196
1197 int exynos5_open(const struct hw_module_t *module, const char *name,
1198 struct hw_device_t **device)
1199 {
1200 int ret = 0;
1201 int refreshRate;
1202
1203 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
1204 return -EINVAL;
1205 }
1206
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));
1210
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);
1215 #endif
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");
1219 ret = -EINVAL;
1220 goto err_get_module;
1221 }
1222
1223 if (gralloc_open((const hw_module_t *)dev->primaryDisplay->mGrallocModule,
1224 &dev->primaryDisplay->mAllocDevice)) {
1225 ALOGE("failed to open gralloc");
1226 ret = -EINVAL;
1227 goto err_get_module;
1228 }
1229 dev->externalDisplay->mAllocDevice = dev->primaryDisplay->mAllocDevice;
1230 #ifdef USES_VIRTUAL_DISPLAY
1231 dev->virtualDisplay->mAllocDevice = dev->primaryDisplay->mAllocDevice;
1232 #endif
1233
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;
1238 goto err_open_fb;
1239 }
1240
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));
1244 ret = -errno;
1245 goto err_ioctl;
1246 }
1247
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;
1252
1253 if (ioctl(dev->primaryDisplay->mDisplayFd, FBIOPUT_VSCREENINFO, &info) == -1) {
1254 ALOGE("FBIOPUT_VSCREENINFO ioctl failed: %s", strerror(errno));
1255 ret = -errno;
1256 goto err_ioctl;
1257 }
1258 }
1259
1260 char value[PROPERTY_VALUE_MAX];
1261 property_get("debug.hwc.force_gpu", value, "0");
1262 dev->force_gpu = atoi(value);
1263
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];
1268
1269 refreshRate = 1000000000000LLU /
1270 (
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 )
1273 * info.pixclock
1274 );
1275
1276 if (refreshRate == 0) {
1277 ALOGW("invalid refresh rate, assuming 60 Hz");
1278 refreshRate = 60;
1279 }
1280
1281 #if defined(USES_DUAL_DISPLAY)
1282 dev->primaryDisplay->mXres = 2 * lcd_xres;
1283 #else
1284 dev->primaryDisplay->mXres = lcd_xres;
1285 #endif
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;
1290
1291 ALOGD("using\n"
1292 "xres = %d px\n"
1293 "yres = %d px\n"
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);
1299 #ifndef USES_VPP
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);
1303 #else
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;
1307 }
1308 #endif
1309 #endif
1310
1311 #ifdef FIMD_WINDOW_OVERLAP_CHECK
1312 /*
1313 * Trivial implementation.
1314 * Effective only for checking the case that
1315 * mMaxWindowOverlapCnt = (NUM_HW_WINDOWS - 1)
1316 */
1317 dev->primaryDisplay->mMaxWindowOverlapCnt =
1318 fimd_window_overlap_limits_init(dev->primaryDisplay->mXres, dev->primaryDisplay->mYres);
1319 #else
1320 dev->primaryDisplay->mMaxWindowOverlapCnt = NUM_HW_WINDOWS;
1321 #endif
1322
1323 if (dev->externalDisplay->openHdmi() < 0) {
1324 ALOGE("openHdmi fail");
1325 }
1326
1327 #if defined(USES_DUAL_DISPLAY)
1328 dev->secondaryDisplay = new ExynosSecondaryDisplayModule(dev);
1329 dev->secondaryDisplay->mAllocDevice = dev->primaryDisplay->mAllocDevice;
1330 #endif
1331 #ifdef USES_VPP
1332 dev->mDisplayResourceManager = new ExynosDisplayResourceManagerModule(dev);
1333 #endif
1334 char devname[MAX_DEV_NAME + 1];
1335 devname[MAX_DEV_NAME] = '\0';
1336
1337 strncpy(devname, VSYNC_DEV_PREFIX, MAX_DEV_NAME);
1338 strlcat(devname, VSYNC_DEV_NAME, MAX_DEV_NAME);
1339
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);
1348 }
1349
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);
1354
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);
1363 }
1364 }
1365
1366 #endif
1367
1368 if (dev->vsync_fd < 0) {
1369 ALOGE("failed to open vsync attribute");
1370 ret = dev->vsync_fd;
1371 goto err_hdmi_open;
1372 } else {
1373 struct stat st;
1374 if (fstat(dev->vsync_fd, &st) < 0) {
1375 ALOGE("Failed to stat vsync node at %s", devname);
1376 goto err_vsync_stat;
1377 }
1378
1379 if (!S_ISREG(st.st_mode)) {
1380 ALOGE("vsync node at %s should be a regualar file", devname);
1381 goto err_vsync_stat;
1382 }
1383 }
1384
1385 dev->psrInfoFd = NULL;
1386
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);
1392
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");
1396 } else {
1397 char val[4];
1398 if (fread(&val, 1, 1, dev->psrInfoFd) == 1) {
1399 dev->psrMode = (0x03 & atoi(val));
1400 dev->panelType = ((0x03 << 2) & atoi(val)) >> 2;
1401 }
1402 }
1403
1404 ALOGI("PSR mode = %d (0: video mode, 1: DP PSR mode, 2: MIPI-DSI command mode)\n",
1405 dev->psrMode);
1406 ALOGI("Panel type = %d (0: Legacy, 1: DSC)\n",
1407 dev->panelType);
1408
1409 #ifdef USES_VPP
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");
1416 } else {
1417 dev->primaryDisplay->mDSCHSliceNum = sliceNum;
1418 dev->primaryDisplay->mDSCYSliceSize = sliceSize;
1419 }
1420 ALOGI("DSC H_Slice_Num: %d, Y_Slice_Size: %d", dev->primaryDisplay->mDSCHSliceNum, dev->primaryDisplay->mDSCYSliceSize);
1421 }
1422 #endif
1423
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;
1428
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;
1442 } else {
1443 dev->base.blank = exynos5_blank;
1444 }
1445
1446 *device = &dev->base.common;
1447
1448 #ifdef IP_SERVICE
1449 android::ExynosIPService *mIPService;
1450 mIPService = android::ExynosIPService::getExynosIPService();
1451 ret = mIPService->createServiceLocked();
1452 if (ret < 0)
1453 goto err_vsync;
1454 #endif
1455
1456 #ifdef HWC_SERVICES
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);
1463 #endif
1464 #endif
1465
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;
1473
1474 #if defined(USES_CEC)
1475 if (dev->hdmi_hpd)
1476 start_cec(dev);
1477 else
1478 dev->mCecFd = -1;
1479 #endif
1480
1481 ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev);
1482 if (ret) {
1483 ALOGE("failed to start vsync thread: %s", strerror(ret));
1484 ret = -ret;
1485 goto err_vsync;
1486 }
1487
1488 #ifdef G2D_COMPOSITION
1489 dev->primaryDisplay->num_of_allocated_lay = 0;
1490 #endif
1491
1492 dev->allowOTF = true;
1493
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;
1499
1500 hwcDebug = 0;
1501
1502 if (dev->hwc_ctrl.dynamic_recomp_mode == true)
1503 exynos5_create_update_stat_thread(dev);
1504
1505 return 0;
1506
1507 err_vsync:
1508 if (dev->psrInfoFd != NULL)
1509 fclose(dev->psrInfoFd);
1510 err_vsync_stat:
1511 close(dev->vsync_fd);
1512 err_hdmi_open:
1513 if (dev->externalDisplay->mDisplayFd > 0)
1514 close(dev->externalDisplay->mDisplayFd);
1515 err_ioctl:
1516 close(dev->primaryDisplay->mDisplayFd);
1517 #if defined(USES_DUAL_DISPLAY)
1518 if (dev->secondaryDisplay->mDisplayFd > 0)
1519 close(dev->secondaryDisplay->mDisplayFd);
1520 #endif
1521 err_open_fb:
1522 gralloc_close(dev->primaryDisplay->mAllocDevice);
1523 err_get_module:
1524 free(dev);
1525 return ret;
1526 }
1527
1528 int exynos5_close(hw_device_t *device)
1529 {
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);
1537 }
1538 #ifndef USES_VPP
1539 for (size_t i = 0; i < NUM_GSC_UNITS; i++)
1540 dev->primaryDisplay->mMPPs[i]->cleanupM2M();
1541 #endif
1542 gralloc_close(dev->primaryDisplay->mAllocDevice);
1543 close(dev->vsync_fd);
1544
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;
1552 }
1553 }
1554 }
1555 #endif
1556
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;
1562 }
1563 }
1564 }
1565 #endif
1566
1567 #ifdef USES_VPP
1568 delete dev->mDisplayResourceManager;
1569 #endif
1570
1571 return 0;
1572 }
1573
1574 static struct hw_module_methods_t exynos5_hwc_module_methods = {
1575 .open = exynos5_open,
1576 };
1577
1578 hwc_module_t HAL_MODULE_INFO_SYM = {
1579 .common = {
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,
1587 .dso = 0,
1588 .reserved = {0},
1589 }
1590 };