exynos: libhwc: Set ioprio for vsync thread
[GitHub/LineageOS/android_hardware_samsung_slsi_exynos.git] / libhwc / ExynosHWC.cpp
CommitLineData
5763fb39
T
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
098e2113 18#include <bfqio/bfqio.h>
5763fb39
T
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <unistd.h>
22#include <utils/Trace.h>
23
24#if defined(USES_CEC)
25#include "libcec.h"
26#endif
27
28#ifdef HWC_SERVICES
29#include "ExynosHWCService.h"
30namespace android {
31class ExynosHWCService;
32}
33#endif
34
35#ifdef IP_SERVICE
36#include "ExynosIPService.h"
37#endif
38
39#include "ExynosHWC.h"
40#include "ExynosHWCUtils.h"
41#include "ExynosMPPModule.h"
42#include "ExynosOverlayDisplay.h"
43#include "ExynosExternalDisplayModule.h"
44#include "ExynosPrimaryDisplay.h"
45#if defined(USES_DUAL_DISPLAY)
46#include "ExynosSecondaryDisplayModule.h"
47#endif
48#ifdef USES_VIRTUAL_DISPLAY
49#include "ExynosVirtualDisplayModule.h"
50#endif
51
52void doPSRExit(struct exynos5_hwc_composer_device_1_t *pdev)
53{
54 int val;
55 int ret;
56 if (pdev->psrMode != PSR_NONE && pdev->notifyPSRExit) {
57 pdev->notifyPSRExit = false;
58 ret = ioctl(pdev->primaryDisplay->mDisplayFd, S3CFB_WIN_PSR_EXIT, &val);
59 }
60}
61
62#if defined(USES_CEC)
63void handle_cec(exynos5_hwc_composer_device_1_t *pdev)
64{
65 unsigned char buffer[16];
66 int size;
67 unsigned char lsrc, ldst, opcode;
68
69 size = CECReceiveMessage(buffer, CEC_MAX_FRAME_SIZE, 1000);
70
71 /* no data available or ctrl-c */
72 if (!size)
73 return;
74
75 /* "Polling Message" */
76 if (size == 1)
77 return;
78
79 lsrc = buffer[0] >> 4;
80
81 /* ignore messages with src address == mCecLaddr */
82 if (lsrc == pdev->mCecLaddr)
83 return;
84
85 opcode = buffer[1];
86
87 if (CECIgnoreMessage(opcode, lsrc)) {
88 ALOGE("### ignore message coming from address 15 (unregistered)");
89 return;
90 }
91
92 if (!CECCheckMessageSize(opcode, size)) {
93 /*
94 * For some reason the TV sometimes sends messages that are too long
95 * Dropping these causes the connect process to fail, so for now we
96 * simply ignore the extra data and process the message as if it had
97 * the correct size
98 */
99 ALOGD("### invalid message size: %d(opcode: 0x%x) ###", size, opcode);
100 }
101
102 /* check if message broadcasted/directly addressed */
103 if (!CECCheckMessageMode(opcode, (buffer[0] & 0x0F) == CEC_MSG_BROADCAST ? 1 : 0)) {
104 ALOGE("### invalid message mode (directly addressed/broadcast) ###");
105 return;
106 }
107
108 ldst = lsrc;
109
110 /* TODO: macros to extract src and dst logical addresses */
111 /* TODO: macros to extract opcode */
112
113 switch (opcode) {
114 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
115 /* respond with "Report Physical Address" */
116 buffer[0] = (pdev->mCecLaddr << 4) | CEC_MSG_BROADCAST;
117 buffer[1] = CEC_OPCODE_REPORT_PHYSICAL_ADDRESS;
118 buffer[2] = (pdev->mCecPaddr >> 8) & 0xFF;
119 buffer[3] = pdev->mCecPaddr & 0xFF;
120 buffer[4] = 3;
121 size = 5;
122 break;
123
124 case CEC_OPCODE_SET_STREAM_PATH:
125 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
126 /* respond with "Active Source" */
127 buffer[0] = (pdev->mCecLaddr << 4) | CEC_MSG_BROADCAST;
128 buffer[1] = CEC_OPCODE_ACTIVE_SOURCE;
129 buffer[2] = (pdev->mCecPaddr >> 8) & 0xFF;
130 buffer[3] = pdev->mCecPaddr & 0xFF;
131 size = 4;
132 break;
133
134 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
135 /* respond with "Report Power Status" */
136 buffer[0] = (pdev->mCecLaddr << 4) | ldst;
137 buffer[1] = CEC_OPCODE_REPORT_POWER_STATUS;
138 buffer[2] = 0;
139 size = 3;
140 break;
141
142 case CEC_OPCODE_REPORT_POWER_STATUS:
143 /* send Power On message */
144 buffer[0] = (pdev->mCecLaddr << 4) | ldst;
145 buffer[1] = CEC_OPCODE_USER_CONTROL_PRESSED;
146 buffer[2] = 0x6D;
147 size = 3;
148 break;
149
150 case CEC_OPCODE_USER_CONTROL_PRESSED:
151 buffer[0] = (pdev->mCecLaddr << 4) | ldst;
152 size = 1;
153 break;
154 case CEC_OPCODE_GIVE_DECK_STATUS:
155 /* respond with "Deck Status" */
156 buffer[0] = (pdev->mCecLaddr << 4) | ldst;
157 buffer[1] = CEC_OPCODE_DECK_STATUS;
158 buffer[2] = 0x11;
159 size = 3;
160 break;
161
162 case CEC_OPCODE_ABORT:
163 case CEC_OPCODE_FEATURE_ABORT:
164 default:
165 /* send "Feature Abort" */
166 buffer[0] = (pdev->mCecLaddr << 4) | ldst;
167 buffer[1] = CEC_OPCODE_FEATURE_ABORT;
168 buffer[2] = CEC_OPCODE_ABORT;
169 buffer[3] = 0x04;
170 size = 4;
171 break;
172 }
173
174 if (CECSendMessage(buffer, size) != size)
175 ALOGE("CECSendMessage() failed!!!");
176}
177
178void start_cec(exynos5_hwc_composer_device_1_t *pdev)
179{
180 unsigned char buffer[CEC_MAX_FRAME_SIZE];
181 int size;
182 pdev->mCecFd = CECOpen();
183 pdev->mCecPaddr = CEC_NOT_VALID_PHYSICAL_ADDRESS;
184 pdev->mCecPaddr = pdev->externalDisplay->getCecPaddr();
185 if (pdev->mCecPaddr < 0) {
186 ALOGE("Error getting physical address");
187 return;
188 }
189 pdev->mCecLaddr = CECAllocLogicalAddress(pdev->mCecPaddr, CEC_DEVICE_PLAYER);
190 /* Request power state from TV */
191 buffer[0] = (pdev->mCecLaddr << 4);
192 buffer[1] = CEC_OPCODE_GIVE_DEVICE_POWER_STATUS;
193 size = 2;
194 if (CECSendMessage(buffer, size) != size)
195 ALOGE("CECSendMessage(%#x) failed!!!", buffer[0]);
196}
197#endif
198
199void exynos5_boot_finished(exynos5_hwc_composer_device_1_t *dev)
200{
201 ALOGD("Boot Finished");
202 int sw_fd;
203 exynos5_hwc_composer_device_1_t *pdev =
204 (exynos5_hwc_composer_device_1_t *)dev;
205 if (pdev == NULL) {
206 ALOGE("%s:: dev is NULL", __func__);
207 return;
208 }
209 sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY);
210
211 if (sw_fd >= 0) {
212 char val;
213 if (read(sw_fd, &val, 1) == 1 && val == '1') {
214 if (pdev->hdmi_hpd != 1) {
215 pdev->hdmi_hpd = true;
216 if ((pdev->externalDisplay->openHdmi() > 0) && pdev->externalDisplay->getConfig()) {
217 ALOGE("Error reading HDMI configuration");
218 pdev->hdmi_hpd = false;
219 }
220 pdev->externalDisplay->mBlanked = false;
221#if defined(USES_CEC)
222 start_cec(pdev);
223#endif
224 if (pdev->procs) {
225 pdev->procs->hotplug(pdev->procs, HWC_DISPLAY_EXTERNAL, true);
226 pdev->procs->invalidate(pdev->procs);
227 }
228 }
229 }
230 close(sw_fd);
231 }
232}
233
234int exynos5_prepare(hwc_composer_device_1_t *dev,
235 size_t numDisplays, hwc_display_contents_1_t** displays)
236{
237 ATRACE_CALL();
238 if (!numDisplays || !displays)
239 return 0;
240
241 exynos5_hwc_composer_device_1_t *pdev =
242 (exynos5_hwc_composer_device_1_t *)dev;
243#if defined(USES_DUAL_DISPLAY)
244 hwc_display_contents_1_t *fimd_contents = displays[HWC_DISPLAY_PRIMARY0];
245 hwc_display_contents_1_t *fimd_contents1 = displays[HWC_DISPLAY_PRIMARY1];
246#else
247 hwc_display_contents_1_t *fimd_contents = displays[HWC_DISPLAY_PRIMARY];
248#endif
249
250 hwc_display_contents_1_t *hdmi_contents = displays[HWC_DISPLAY_EXTERNAL];
251#ifdef USES_VIRTUAL_DISPLAY
252 hwc_display_contents_1_t *virtual_contents = displays[HWC_DISPLAY_VIRTUAL];
253 if (virtual_contents == NULL)
254 pdev->virtualDisplay->deInit();
255#ifdef USES_VIRTUAL_DISPLAY_DECON_EXT_WB
256 if (virtual_contents)
257 pdev->virtualDisplay->init(virtual_contents);
258#endif
259#endif
260 pdev->updateCallCnt++;
261 pdev->update_event_cnt++;
262 pdev->LastUpdateTimeStamp = systemTime(SYSTEM_TIME_MONOTONIC);
263 pdev->primaryDisplay->getCompModeSwitch();
264 pdev->totPixels = 0;
265 pdev->incomingPixels = 0;
266
267#if defined(USES_DUAL_DISPLAY)
268 if (pdev->hdmi_hpd || (fimd_contents1 == NULL) ||
269 (fimd_contents1->numHwLayers <= 1)) {
270 if (pdev->secondaryDisplay->mEnabled)
271 pdev->secondaryDisplay->disable();
272 }
273#endif
274
275 pdev->externalDisplay->setHdmiStatus(pdev->hdmi_hpd);
276
277#if defined(USES_DUAL_DISPLAY)
278 if (!pdev->hdmi_hpd && fimd_contents1 &&
279 (fimd_contents1->numHwLayers > 1)) {
280 if (!pdev->secondaryDisplay->mEnabled)
281 pdev->secondaryDisplay->enable();
282 }
283#endif
284
285 if (pdev->hwc_ctrl.dynamic_recomp_mode == true &&
286 pdev->update_stat_thread_flag == false &&
287 pdev->primaryDisplay->mBlanked == false) {
288 exynos5_create_update_stat_thread(pdev);
289 }
290
291#ifdef USES_VPP
292 pdev->mDisplayResourceManager->assignResources(numDisplays, displays);
293#endif
294
295 if (fimd_contents) {
296 android::Mutex::Autolock lock(pdev->primaryDisplay->mLayerInfoMutex);
297 int err = pdev->primaryDisplay->prepare(fimd_contents);
298 if (err)
299 return err;
300 }
301 if (hdmi_contents) {
302 android::Mutex::Autolock lock(pdev->externalDisplay->mLayerInfoMutex);
303 int err = 0;
304 err = pdev->externalDisplay->prepare(hdmi_contents);
305 if (err)
306 return err;
307 }
308#if defined(USES_DUAL_DISPLAY)
309 if ((pdev->hdmi_hpd == false) && fimd_contents1) {
310 android::Mutex::Autolock lock(pdev->secondaryDisplay->mLayerInfoMutex);
311 int err = pdev->secondaryDisplay->prepare(fimd_contents1);
312 if (err)
313 return err;
314 }
315#endif
316
317
318#ifdef USES_VIRTUAL_DISPLAY
319 if (virtual_contents) {
320#ifdef USES_VIRTUAL_DISPLAY_DECON_EXT_WB
321 ExynosVirtualDisplayModule *virDisplay = (ExynosVirtualDisplayModule *)pdev->virtualDisplay;
322 virDisplay->setPriContents(fimd_contents);
323#endif
324 int err = pdev->virtualDisplay->prepare(virtual_contents);
325 if (err)
326 return err;
327 }
328#endif
329
330 return 0;
331}
332
333int exynos5_set(struct hwc_composer_device_1 *dev,
334 size_t numDisplays, hwc_display_contents_1_t** displays)
335{
336 ATRACE_CALL();
337 if (!numDisplays || !displays)
338 return 0;
339
340 exynos5_hwc_composer_device_1_t *pdev =
341 (exynos5_hwc_composer_device_1_t *)dev;
342#if defined(USES_DUAL_DISPLAY)
343 hwc_display_contents_1_t *fimd_contents = displays[HWC_DISPLAY_PRIMARY0];
344 hwc_display_contents_1_t *fimd_contents1 = displays[HWC_DISPLAY_PRIMARY1];
345#else
346 hwc_display_contents_1_t *fimd_contents = displays[HWC_DISPLAY_PRIMARY];
347#endif
348 hwc_display_contents_1_t *hdmi_contents = displays[HWC_DISPLAY_EXTERNAL];
349 int fimd_err = 0, hdmi_err = 0;
350#ifdef USES_VIRTUAL_DISPLAY
351 int virtual_err = 0;
352 hwc_display_contents_1_t *virtual_contents = displays[HWC_DISPLAY_VIRTUAL];
353#endif
354
355#if defined(USES_DUAL_DISPLAY)
356 if ((pdev->hdmi_hpd == false) && fimd_contents1) {
357 hdmi_err = pdev->secondaryDisplay->set(fimd_contents1);
358 }
359#endif
360
361 if (fimd_contents) {
362 android::Mutex::Autolock lock(pdev->primaryDisplay->mLayerInfoMutex);
363#if defined(USES_DUAL_DISPLAY)
364 fimd_err = pdev->primaryDisplay->set_dual(fimd_contents, fimd_contents1);
365#else
366 fimd_err = pdev->primaryDisplay->set(fimd_contents);
367#endif
368 }
369
370 if (pdev->mS3DMode != S3D_MODE_STOPPING && !pdev->mHdmiResolutionHandled) {
371 pdev->mHdmiResolutionHandled = true;
372 pdev->hdmi_hpd = true;
373 pdev->externalDisplay->enable();
374 if (pdev->procs) {
375 pdev->procs->hotplug(pdev->procs, HWC_DISPLAY_EXTERNAL, true);
376 pdev->procs->invalidate(pdev->procs);
377 }
378 }
379
380 if (hdmi_contents && fimd_contents) {
381 android::Mutex::Autolock lock(pdev->externalDisplay->mLayerInfoMutex);
382 hdmi_err = pdev->externalDisplay->set(hdmi_contents);
383 }
384
385 if (pdev->hdmi_hpd && pdev->mHdmiResolutionChanged) {
386 if (pdev->mS3DMode == S3D_MODE_DISABLED && pdev->externalDisplay->isPresetSupported(pdev->mHdmiPreset))
387 pdev->externalDisplay->setPreset(pdev->mHdmiPreset);
388 }
389 if (pdev->mS3DMode == S3D_MODE_STOPPING) {
390 pdev->mS3DMode = S3D_MODE_DISABLED;
391#ifndef USES_VPP
392 for (int i = 0; i < pdev->primaryDisplay->mNumMPPs; i++)
393 pdev->primaryDisplay->mMPPs[i]->mS3DMode = S3D_NONE;
394
395 if (pdev->externalDisplay->mMPPs[0] != NULL)
396 pdev->externalDisplay->mMPPs[0]->mS3DMode = S3D_NONE;
397#endif
398 }
399
400#ifdef USES_VIRTUAL_DISPLAY
401 if (virtual_contents && fimd_contents)
402 virtual_err = pdev->virtualDisplay->set(virtual_contents);
403#endif
404
405#ifdef EXYNOS_SUPPORT_PSR_EXIT
406 pdev->notifyPSRExit = true;
407#else
408 pdev->notifyPSRExit = false;
409#endif
410
411 pdev->primaryDisplay->freeMPP();
412
413#ifdef USES_VPP
414 pdev->mDisplayResourceManager->cleanupMPPs();
415#endif
416
417 if (fimd_err)
418 return fimd_err;
419
420#ifndef USES_VIRTUAL_DISPLAY
421 return hdmi_err;
422#else
423 if (hdmi_err)
424 return hdmi_err;
425
426 return virtual_err;
427#endif
428}
429
430void exynos5_registerProcs(struct hwc_composer_device_1* dev,
431 hwc_procs_t const* procs)
432{
433 struct exynos5_hwc_composer_device_1_t* pdev =
434 (struct exynos5_hwc_composer_device_1_t*)dev;
435 pdev->procs = procs;
436}
437
438int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value)
439{
440 struct exynos5_hwc_composer_device_1_t *pdev =
441 (struct exynos5_hwc_composer_device_1_t *)dev;
442
443 switch (what) {
444 case HWC_BACKGROUND_LAYER_SUPPORTED:
c8e8b208
DW
445 // we do not support the background layer
446 value[0] = 0;
5763fb39
T
447 break;
448 case HWC_VSYNC_PERIOD:
449 // vsync period in nanosecond
450 value[0] = pdev->primaryDisplay->mVsyncPeriod;
451 break;
452 default:
453 // unsupported query
454 return -EINVAL;
455 }
456 return 0;
457}
458
459int exynos5_eventControl(struct hwc_composer_device_1 *dev, int __unused dpy,
460 int event, int enabled)
461{
462 struct exynos5_hwc_composer_device_1_t *pdev =
463 (struct exynos5_hwc_composer_device_1_t *)dev;
464
465 switch (event) {
466 case HWC_EVENT_VSYNC:
467 __u32 val = !!enabled;
468 pdev->VsyncInterruptStatus = val;
469 int err = ioctl(pdev->primaryDisplay->mDisplayFd, S3CFB_SET_VSYNC_INT, &val);
470 if (err < 0) {
471 ALOGE("vsync ioctl failed");
472 return -errno;
473 }
474 return 0;
475 }
476
477 return -EINVAL;
478}
479
480void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev,
481 const char *buff, int len)
482{
483 const char *s = buff;
484 s += strlen(s) + 1;
485
486 while (*s) {
487 if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
488 pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1;
489
490 s += strlen(s) + 1;
491 if (s - buff >= len)
492 break;
493 }
494
495 if (pdev->hdmi_hpd) {
496 if ((pdev->externalDisplay->openHdmi() > 0) && pdev->externalDisplay->getConfig()) {
497 ALOGE("Error reading HDMI configuration");
498 pdev->hdmi_hpd = false;
499 return;
500 }
501
502 pdev->externalDisplay->mBlanked = false;
503#if defined(USES_CEC)
504 start_cec(pdev);
505 } else {
506 CECClose();
507 pdev->mCecFd = -1;
508 }
509#else
510 }
511#endif
512
513 ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled");
514 if (pdev->hdmi_hpd)
515 ALOGI("HDMI Resolution changed to %dx%d",
516 pdev->externalDisplay->mXres, pdev->externalDisplay->mYres);
517
518 /* hwc_dev->procs is set right after the device is opened, but there is
519 * still a race condition where a hotplug event might occur after the open
520 * but before the procs are registered. */
521 if (pdev->procs)
522 pdev->procs->hotplug(pdev->procs, HWC_DISPLAY_EXTERNAL, pdev->hdmi_hpd);
523}
524
e869a272
DW
525void handle_tui_uevent(struct exynos5_hwc_composer_device_1_t *pdev __unused,
526 const char *buff __unused, int len __unused)
5763fb39
T
527{
528#ifdef USES_VPP
529#ifdef DISABLE_IDMA_SECURE
530 return;
531#else
532 const char *s = buff;
533 unsigned int tui_disabled = 1;
534 bool useSecureDMA = true;
535 s += strlen(s) + 1;
536
537 while (*s) {
538 if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
539 tui_disabled = atoi(s + strlen("SWITCH_STATE=")) == 0;
540
541 s += strlen(s) + 1;
542 if (s - buff >= len)
543 break;
544 }
545
546 if (tui_disabled)
547 useSecureDMA = true;
548 else
549 useSecureDMA = false;
550
551 ALOGI("TUI mode is %s", tui_disabled ? "disabled" : "enabled");
552
553 if (pdev->primaryDisplay->mUseSecureDMA != useSecureDMA) {
554 pdev->primaryDisplay->mUseSecureDMA = useSecureDMA;
555 if ((pdev->procs) && (pdev->procs->invalidate))
556 pdev->procs->invalidate(pdev->procs);
557 }
558#endif
559#endif
560}
561
562void handle_vsync_event(struct exynos5_hwc_composer_device_1_t *pdev)
563{
564 if (!pdev->procs)
565 return;
566
567 int err = lseek(pdev->vsync_fd, 0, SEEK_SET);
568 if (err < 0) {
569 ALOGE("error seeking to vsync timestamp: %s", strerror(errno));
570 return;
571 }
572
573 char buf[4096];
574 err = read(pdev->vsync_fd, buf, sizeof(buf));
575 if (err < 0) {
576 ALOGE("error reading vsync timestamp: %s", strerror(errno));
577 return;
578 }
579 buf[sizeof(buf) - 1] = '\0';
580
581 errno = 0;
582 uint64_t timestamp = strtoull(buf, NULL, 0);
583 if (!errno)
584 pdev->procs->vsync(pdev->procs, 0, timestamp);
585}
586
587void *hwc_update_stat_thread(void *data)
588{
589 struct exynos5_hwc_composer_device_1_t *pdev =
590 (struct exynos5_hwc_composer_device_1_t *)data;
591 int event_cnt = 0;
592
593 while (pdev->update_stat_thread_flag) {
594 event_cnt = pdev->update_event_cnt;
595 /*
596 * If there is no update for more than 100ms, favor the 3D composition mode.
597 * If all other conditions are met, mode will be switched to 3D composition.
598 */
599 usleep(100000);
600 if (event_cnt == pdev->update_event_cnt) {
601 if (pdev->primaryDisplay->getCompModeSwitch() == HWC_2_GLES) {
602 if ((pdev->procs) && (pdev->procs->invalidate)) {
603 pdev->update_event_cnt = 0;
604 pdev->procs->invalidate(pdev->procs);
605 }
606 }
607 }
608 }
609 return NULL;
610}
611
612void exynos5_create_update_stat_thread(struct exynos5_hwc_composer_device_1_t *dev)
613{
614 /* pthread_create shouldn't have ben failed. But, ignore even if some error */
615 if (pthread_create(&dev->update_stat_thread, NULL, hwc_update_stat_thread, dev) != 0) {
616 ALOGE("%s: failed to start update_stat thread:", __func__);
617 dev->update_stat_thread_flag = false;
618 } else {
619 dev->update_stat_thread_flag = true;
620 }
621}
622
623void *hwc_vsync_thread(void *data)
624{
625 struct exynos5_hwc_composer_device_1_t *pdev =
626 (struct exynos5_hwc_composer_device_1_t *)data;
627 char uevent_desc[4096];
628 memset(uevent_desc, 0, sizeof(uevent_desc));
629
748becfc
EW
630 struct sched_param sched_param = {0};
631 sched_param.sched_priority = 5;
632 if (sched_setscheduler(gettid(), SCHED_FIFO, &sched_param) != 0) {
633 ALOGE("Couldn't set SCHED_FIFO for hwc_vsync");
634 }
098e2113 635 android_set_rt_ioprio(0, 1);
5763fb39
T
636
637 uevent_init();
638
639 char temp[4096];
640 int err = read(pdev->vsync_fd, temp, sizeof(temp));
641 if (err < 0) {
642 ALOGE("error reading vsync timestamp: %s", strerror(errno));
643 return NULL;
644 }
645
646#if defined(USES_CEC)
647 struct pollfd fds[3];
648#else
649 struct pollfd fds[2];
650#endif
651 fds[0].fd = pdev->vsync_fd;
652 fds[0].events = POLLPRI;
653 fds[1].fd = uevent_get_fd();
654 fds[1].events = POLLIN;
655#if defined(USES_CEC)
656 fds[2].fd = pdev->mCecFd;
657 fds[2].events = POLLIN;
658#endif
659
660 while (true) {
661#if defined(USES_CEC)
662 int err;
663 fds[2].fd = pdev->mCecFd;
664 if (fds[2].fd > 0)
665 err = poll(fds, 3, -1);
666 else
667 err = poll(fds, 2, -1);
668#else
669 int err = poll(fds, 2, -1);
670#endif
671
672 if (err > 0) {
673 if (fds[0].revents & POLLPRI) {
674 handle_vsync_event(pdev);
675 }
676 else if (fds[1].revents & POLLIN) {
677 int len = uevent_next_event(uevent_desc,
678 sizeof(uevent_desc) - 2);
679
680 bool hdmi = !strcmp(uevent_desc,
681 "change@/devices/virtual/switch/hdmi");
682 bool tui_status = !strcmp(uevent_desc,
683 "change@/devices/virtual/switch/tui");
684
685 if (hdmi)
686 handle_hdmi_uevent(pdev, uevent_desc, len);
687 else if (tui_status)
688 handle_tui_uevent(pdev, uevent_desc, len);
689#if defined(USES_CEC)
690 } else if (pdev->hdmi_hpd && fds[2].revents & POLLIN) {
691 handle_cec(pdev);
692#endif
693 }
694 }
695 else if (err == -1) {
696 if (errno == EINTR)
697 break;
698 ALOGE("error in vsync thread: %s", strerror(errno));
699 }
700 }
701
702 return NULL;
703}
704
705int exynos5_blank(struct hwc_composer_device_1 *dev, int disp, int blank)
706{
707 ATRACE_CALL();
5763fb39
T
708 struct exynos5_hwc_composer_device_1_t *pdev =
709 (struct exynos5_hwc_composer_device_1_t *)dev;
710#ifdef SKIP_DISPLAY_BLANK_CTRL
711 return 0;
712#endif
713 ALOGI("%s:: disp(%d), blank(%d)", __func__, disp, blank);
714 switch (disp) {
715 case HWC_DISPLAY_PRIMARY: {
716 int fb_blank = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
717 if (fb_blank == FB_BLANK_POWERDOWN) {
718 int fence = pdev->primaryDisplay->clearDisplay();
719 if (fence < 0) {
720 HLOGE("error clearing primary display");
721 } else {
722#ifndef USES_VPP
723 if (pdev->primaryDisplay->mGscUsed && pdev->primaryDisplay->mMPPs[FIMD_GSC_IDX]->isOTF())
724 pdev->primaryDisplay->mMPPs[FIMD_GSC_IDX]->cleanupOTF();
725#endif
726 close(fence);
727 }
728 }
729#if !defined(HDMI_ON_IN_SUSPEND) && defined(CHANGE_POWEROFF_SEQ)
730 /*
731 * LCD power block shouldn't be turned off
732 * before TV power block is turned off in Exynos4.
733 */
734 if (pdev->hdmi_hpd) {
735 if (blank && !pdev->externalDisplay->mBlanked) {
736 pdev->externalDisplay->disable();
737 }
738 pdev->externalDisplay->mBlanked = !!blank;
739 }
740#endif
741 pdev->primaryDisplay->mBlanked = !!blank;
742
a7b85743
DW
743 /* Check if the thread is enabled before calling pthread_kill as we will seg fault otherwise */
744 if(pdev->update_stat_thread_flag == true) {
745 if (pthread_kill(pdev->update_stat_thread, 0) != ESRCH) { //check if the thread is alive
746 if (fb_blank == FB_BLANK_POWERDOWN) {
747 pdev->update_stat_thread_flag = false;
748 pthread_join(pdev->update_stat_thread, 0);
749 }
5763fb39
T
750 }
751 } else { // thread is not alive
752 if (fb_blank == FB_BLANK_UNBLANK && pdev->hwc_ctrl.dynamic_recomp_mode == true)
753 exynos5_create_update_stat_thread(pdev);
754 }
755#if defined(USES_DUAL_DISPLAY)
756 struct decon_dual_display_blank_data blank_data;
757 memset(&blank_data, 0, sizeof(blank_data));
758 blank_data.display_type = blank_data.DECON_PRIMARY_DISPLAY;
759 blank_data.blank = fb_blank;
760 int err = ioctl(pdev->primaryDisplay->mDisplayFd, S3CFB_DUAL_DISPLAY_BLANK, &blank_data);
761#else
762 int err = ioctl(pdev->primaryDisplay->mDisplayFd, FBIOBLANK, fb_blank);
763#endif
764 if (err < 0) {
765 if (errno == EBUSY)
766 ALOGI("%sblank ioctl failed (display already %sblanked)",
767 blank ? "" : "un", blank ? "" : "un");
768 else
769 ALOGE("%sblank ioctl failed: %s", blank ? "" : "un",
770 strerror(errno));
771 return -errno;
772 }
773 break;
774 }
775#if defined(USES_DUAL_DISPLAY)
776 case HWC_DISPLAY_PRIMARY1: {
777 int fb_blank = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
778 /* To do: Should be implemented */
779 pdev->secondaryDisplay->mBlanked = !!blank;
780 struct decon_dual_display_blank_data blank_data;
781 memset(&blank_data, 0, sizeof(blank_data));
782 blank_data.display_type = blank_data.DECON_SECONDARY_DISPLAY;
783 blank_data.blank = fb_blank;
784 int err = ioctl(pdev->primaryDisplay->mDisplayFd, S3CFB_DUAL_DISPLAY_BLANK, &blank_data);
785 break;
786 }
787#endif
788 case HWC_DISPLAY_EXTERNAL:
789#if !defined(HDMI_ON_IN_SUSPEND) && !defined(CHANGE_POWEROFF_SEQ)
790 if (pdev->hdmi_hpd) {
791 if (blank && !pdev->externalDisplay->mBlanked) {
792 pdev->externalDisplay->disable();
793 }
794 pdev->externalDisplay->mBlanked = !!blank;
795 }
796#else
797 fence = pdev->externalDisplay->clearDisplay();
798 if (fence >= 0)
799 close(fence);
800 pdev->externalDisplay->mBlanked = !!blank;
801#endif
802 break;
803
804 default:
805 return -EINVAL;
806
807 }
808
809 return 0;
810}
811
812void exynos5_dump(hwc_composer_device_1* dev, char *buff, int buff_len)
813{
814 if (buff_len <= 0)
815 return;
816
817 struct exynos5_hwc_composer_device_1_t *pdev =
818 (struct exynos5_hwc_composer_device_1_t *)dev;
819
820 android::String8 result;
821
822 result.appendFormat("\n hdmi_enabled=%u\n", pdev->externalDisplay->mEnabled);
823 if (pdev->externalDisplay->mEnabled)
824 result.appendFormat(" w=%u, h=%u\n", pdev->externalDisplay->mXres, pdev->externalDisplay->mYres);
825
826 result.append("Primary device's config information\n");
827 pdev->primaryDisplay->dump(result);
828
829#ifdef USES_VPP
830 if (pdev->hdmi_hpd) {
831 result.append("\n");
832 result.append("External device's config information\n");
833 pdev->externalDisplay->dump(result);
834 }
835#if defined(USES_DUAL_DISPLAY)
836 else {
837 result.append("\n");
838 result.append("Secondary device's config information\n");
839 pdev->secondaryDisplay->dump(result);
840 }
841#endif
842#ifdef USES_VIRTUAL_DISPLAY_DECON_EXT_WB
843 if (pdev->virtualDisplay->mIsWFDState) {
844 result.append("\n");
845 result.append("Virtual device's config information\n");
846 pdev->virtualDisplay->dump(result);
847 }
848#endif
849#endif
850 {
851 android::Mutex::Autolock lock(pdev->primaryDisplay->mLayerInfoMutex);
852 result.append("\n");
853 result.append("Primary device's layer information\n");
854 pdev->primaryDisplay->dumpLayerInfo(result);
855 }
856
857 if (pdev->hdmi_hpd) {
858 android::Mutex::Autolock lock(pdev->externalDisplay->mLayerInfoMutex);
859 result.append("\n");
860 result.append("External device's layer information\n");
861 pdev->externalDisplay->dumpLayerInfo(result);
862 }
863#if defined(USES_DUAL_DISPLAY)
864 else {
865 android::Mutex::Autolock lock(pdev->secondaryDisplay->mLayerInfoMutex);
866 result.append("\n");
867 result.append("Secondary device's layer information\n");
868 pdev->secondaryDisplay->dumpLayerInfo(result);
869 }
870#endif
871#if USES_VIRTUAL_DISPLAY_DECON_EXT_WB
872 if (pdev->virtualDisplay->mIsWFDState) {
873 android::Mutex::Autolock lock(pdev->virtualDisplay->mLayerInfoMutex);
874 result.append("\n");
875 result.append("Virtual device's layer information\n");
876 pdev->virtualDisplay->dumpLayerInfo(result);
877 }
878#endif
879 strlcpy(buff, result.string(), buff_len);
880}
881
882int exynos5_getDisplayConfigs(struct hwc_composer_device_1 *dev,
883 int disp, uint32_t *configs, size_t *numConfigs)
884{
885 struct exynos5_hwc_composer_device_1_t *pdev =
886 (struct exynos5_hwc_composer_device_1_t *)dev;
887 int err = 0;
888
889 if (*numConfigs == 0)
890 return 0;
891
892#if defined(USES_DUAL_DISPLAY)
893 if (disp == HWC_DISPLAY_PRIMARY0) {
894 configs[0] = 0;
895 *numConfigs = 1;
896 return 0;
897 } else if (disp == HWC_DISPLAY_PRIMARY1) {
898 configs[0] = 0;
899 *numConfigs = 1;
900 return 0;
901#else
902 if (disp == HWC_DISPLAY_PRIMARY) {
903 configs[0] = 0;
904 *numConfigs = 1;
905 return 0;
906#endif
907 } else if (disp == HWC_DISPLAY_EXTERNAL) {
908 if (!pdev->hdmi_hpd) {
909 return -EINVAL;
910 }
911 if (hwcHasApiVersion((hwc_composer_device_1_t*)dev, HWC_DEVICE_API_VERSION_1_4))
912 err = pdev->externalDisplay->getDisplayConfigs(configs, numConfigs);
913 else {
914 err = pdev->externalDisplay->getConfig();
915 configs[0] = 0;
916 *numConfigs = 1;
917 }
918 if (err) {
919 return -EINVAL;
920 }
921 return 0;
922#ifdef USES_VIRTUAL_DISPLAY
923 } else if (disp == HWC_DISPLAY_VIRTUAL) {
924 int err = pdev->virtualDisplay->getConfig();
925 if (err) {
926 return -EINVAL;
927 }
928 configs[0] = 0;
929 *numConfigs = 1;
930 return 0;
931#endif
932 }
933
934 return -EINVAL;
935}
936
937int32_t exynos5_hdmi_attribute(struct exynos5_hwc_composer_device_1_t *pdev,
938 const uint32_t attribute)
939{
940 switch(attribute) {
941 case HWC_DISPLAY_VSYNC_PERIOD:
942 return pdev->primaryDisplay->mVsyncPeriod;
943
944 case HWC_DISPLAY_WIDTH:
945 return pdev->externalDisplay->mXres;
946
947 case HWC_DISPLAY_HEIGHT:
948 return pdev->externalDisplay->mYres;
949
950 case HWC_DISPLAY_DPI_X:
951 case HWC_DISPLAY_DPI_Y:
952 return 0; // unknown
953
954 default:
955 ALOGE("unknown display attribute %u", attribute);
956 return -EINVAL;
957 }
958}
959
960int exynos5_getDisplayAttributes(struct hwc_composer_device_1 *dev,
961 int disp, uint32_t config, const uint32_t *attributes, int32_t *values)
962{
963 struct exynos5_hwc_composer_device_1_t *pdev =
964 (struct exynos5_hwc_composer_device_1_t *)dev;
965
966 for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
967#if defined(USES_DUAL_DISPLAY)
968 if (disp == HWC_DISPLAY_PRIMARY0)
969 values[i] = pdev->primaryDisplay->getDisplayAttributes(attributes[i]);
970 else if (disp == HWC_DISPLAY_PRIMARY1)
971 values[i] = pdev->secondaryDisplay->getDisplayAttributes(attributes[i]);
972#else
973 if (disp == HWC_DISPLAY_PRIMARY)
1f145ce6 974 values[i] = pdev->primaryDisplay->getDisplayAttributes(attributes[i], config);
5763fb39
T
975#endif
976 else if (disp == HWC_DISPLAY_EXTERNAL) {
977 if (hwcHasApiVersion((hwc_composer_device_1_t*)dev, HWC_DEVICE_API_VERSION_1_4))
978 values[i] = pdev->externalDisplay->getDisplayAttributes(attributes[i], config);
979 else
980 values[i] = exynos5_hdmi_attribute(pdev, attributes[i]);
981 }
982#ifdef USES_VIRTUAL_DISPLAY
983 else if (disp == HWC_DISPLAY_VIRTUAL)
984 values[i] = pdev->virtualDisplay->getDisplayAttributes(attributes[i]);
985#endif
986 else {
987 ALOGE("unknown display type %u", disp);
988 return -EINVAL;
989 }
990 }
991
992 return 0;
993}
994
995int exynos_getActiveConfig(struct hwc_composer_device_1* dev, int disp)
996{
997 struct exynos5_hwc_composer_device_1_t *pdev =
998 (struct exynos5_hwc_composer_device_1_t *)dev;
999 if (disp == HWC_DISPLAY_PRIMARY)
1000 return 0;
1001 else if (disp == HWC_DISPLAY_EXTERNAL) {
1002 if (pdev->hdmi_hpd) {
1003 if (hwcHasApiVersion((hwc_composer_device_1_t*)dev, HWC_DEVICE_API_VERSION_1_4))
1004 return pdev->externalDisplay->getActiveConfig();
1005 else
1006 return 0;
1007 } else {
1008 ALOGE("%s::External device is not connected", __func__);
1009 return -1;
1010 }
1011 } else if (disp == HWC_DISPLAY_VIRTUAL)
1012 return 0;
1013 else {
1014 ALOGE("%s:: unknown display type %u", __func__, disp);
1015 return -EINVAL;
1016 }
1017}
1018
1019int exynos_setActiveConfig(struct hwc_composer_device_1* dev, int disp, int index)
1020{
1021 struct exynos5_hwc_composer_device_1_t *pdev =
1022 (struct exynos5_hwc_composer_device_1_t *)dev;
1023 ALOGI("%s:: disp(%d), index(%d)", __func__, disp, index);
1024 if (disp == HWC_DISPLAY_PRIMARY) {
1025 if (index != 0) {
1026 ALOGE("%s::Primary display doen't support index(%d)", __func__, index);
1027 return -1;
1028 }
1029 return 0;
1030 }
1031 else if (disp == HWC_DISPLAY_EXTERNAL) {
1032 if (pdev->hdmi_hpd) {
1033 if (hwcHasApiVersion((hwc_composer_device_1_t*)dev, HWC_DEVICE_API_VERSION_1_4)) {
1034 return pdev->externalDisplay->setActiveConfig(index);
1035 } else {
1036 if (index != 0) {
1037 ALOGE("%s::External display doen't support index(%d)", __func__, index);
1038 return -1;
1039 } else {
1040 return 0;
1041 }
1042 }
1043 } else {
1044 ALOGE("%s::External device is not connected", __func__);
1045 return -1;
1046 }
1047 } else if (disp == HWC_DISPLAY_VIRTUAL)
1048 return 0;
1049
1050 return -1;
1051}
1052
55264519 1053int exynos_setCursorPositionAsync(struct hwc_composer_device_1 *dev __unused, int disp __unused, int x_pos __unused, int y_pos __unused)
5763fb39
T
1054{
1055 return 0;
1056}
1057
1058int exynos_setPowerMode(struct hwc_composer_device_1* dev, int disp, int mode)
1059{
1060 ATRACE_CALL();
5763fb39
T
1061 struct exynos5_hwc_composer_device_1_t *pdev =
1062 (struct exynos5_hwc_composer_device_1_t *)dev;
1063#ifdef SKIP_DISPLAY_BLANK_CTRL
1064 return 0;
1065#endif
1066 ALOGI("%s:: disp(%d), mode(%d)", __func__, disp, mode);
1067 int fb_blank = 0;
1068 int blank = 0;
1069 if (mode == HWC_POWER_MODE_OFF) {
1070 fb_blank = FB_BLANK_POWERDOWN;
1071 blank = 1;
1072 } else {
1073 fb_blank = FB_BLANK_UNBLANK;
1074 blank = 0;
1075 }
1076
1077 switch (disp) {
1078 case HWC_DISPLAY_PRIMARY: {
1079#ifdef USES_VPP
1080 if ((mode == HWC_POWER_MODE_DOZE) || (mode == HWC_POWER_MODE_DOZE_SUSPEND)) {
1a0fa771
SS
1081 if (pdev->primaryDisplay->mBlanked == 1) {
1082 fb_blank = FB_BLANK_UNBLANK;
5763fb39
T
1083 int err = ioctl(pdev->primaryDisplay->mDisplayFd, FBIOBLANK, fb_blank);
1084 if (err < 0) {
1085 ALOGE("blank ioctl failed: %s, mode(%d)", strerror(errno), mode);
1086 return -errno;
1087 }
1088 }
1a0fa771 1089 pdev->primaryDisplay->mBlanked = 0;
5763fb39
T
1090 return pdev->primaryDisplay->setPowerMode(mode);
1091 }
1092#endif
1093 if (fb_blank == FB_BLANK_POWERDOWN) {
1094 int fence = -1;
1095#if defined(USES_DUAL_DISPLAY)
1096 if (pdev->secondaryDisplay->mBlanked)
1097#endif
1098 fence = pdev->primaryDisplay->clearDisplay();
1099 if (fence < 0) {
1100 HLOGE("error clearing primary display");
1101 } else {
1102#ifndef USES_VPP
1103 if (pdev->primaryDisplay->mGscUsed && pdev->primaryDisplay->mMPPs[FIMD_GSC_IDX]->isOTF())
1104 pdev->primaryDisplay->mMPPs[FIMD_GSC_IDX]->cleanupOTF();
1105#endif
1106 close(fence);
1107 }
1108 }
1109#if !defined(HDMI_ON_IN_SUSPEND) && defined(CHANGE_POWEROFF_SEQ)
1110 /*
1111 * LCD power block shouldn't be turned off
1112 * before TV power block is turned off in Exynos4.
1113 */
1114 if (pdev->hdmi_hpd) {
1115 if (blank && !pdev->externalDisplay->mBlanked) {
1116 pdev->externalDisplay->disable();
1117 }
1118 pdev->externalDisplay->mBlanked = !!blank;
1119 }
1120#endif
1121 pdev->primaryDisplay->mBlanked = !!blank;
1122
a7b85743
DW
1123 /* Check if the thread is enabled before calling pthread_kill as we will seg fault otherwise */
1124 if(pdev->update_stat_thread_flag == true) {
1125 if (pthread_kill(pdev->update_stat_thread, 0) != ESRCH) { //check if the thread is alive
1126 if (fb_blank == FB_BLANK_POWERDOWN) {
1127 pdev->update_stat_thread_flag = false;
1128 pthread_join(pdev->update_stat_thread, 0);
1129 }
5763fb39
T
1130 }
1131 } else { // thread is not alive
1132 if (fb_blank == FB_BLANK_UNBLANK && pdev->hwc_ctrl.dynamic_recomp_mode == true)
1133 exynos5_create_update_stat_thread(pdev);
1134 }
1135#if defined(USES_DUAL_DISPLAY)
1136 struct decon_dual_display_blank_data blank_data;
1137 memset(&blank_data, 0, sizeof(blank_data));
1138 blank_data.display_type = blank_data.DECON_PRIMARY_DISPLAY;
1139 blank_data.blank = fb_blank;
1140 int err = ioctl(pdev->primaryDisplay->mDisplayFd, S3CFB_DUAL_DISPLAY_BLANK, &blank_data);
1141#else
1142 int err = ioctl(pdev->primaryDisplay->mDisplayFd, FBIOBLANK, fb_blank);
1143#endif
1144 if (err < 0) {
1145 if (errno == EBUSY)
1146 ALOGI("%sblank ioctl failed (display already %sblanked)",
1147 blank ? "" : "un", blank ? "" : "un");
1148 else
1149 ALOGE("%sblank ioctl failed: %s", blank ? "" : "un",
1150 strerror(errno));
1151 return -errno;
1152 }
1153 break;
1154 }
1155#if defined(USES_DUAL_DISPLAY)
1156 case HWC_DISPLAY_PRIMARY1: {
1157 if (fb_blank == FB_BLANK_POWERDOWN) {
1158 int fence = -1;
1159 if (pdev->primaryDisplay->mBlanked)
1160 fence = pdev->primaryDisplay->clearDisplay();
1161 if (fence < 0) {
1162 HLOGE("error clearing primary display");
1163 } else {
1164 close(fence);
1165 }
1166 }
1167 /* To do: Should be implemented */
1168 pdev->secondaryDisplay->mBlanked = !!blank;
1169 struct decon_dual_display_blank_data blank_data;
1170 memset(&blank_data, 0, sizeof(blank_data));
1171 blank_data.display_type = blank_data.DECON_SECONDARY_DISPLAY;
1172 blank_data.blank = fb_blank;
1173 int err = ioctl(pdev->primaryDisplay->mDisplayFd, S3CFB_DUAL_DISPLAY_BLANK, &blank_data);
1174 break;
1175 }
1176#endif
1177 case HWC_DISPLAY_EXTERNAL:
1178#if !defined(HDMI_ON_IN_SUSPEND) && !defined(CHANGE_POWEROFF_SEQ)
1179 if (pdev->hdmi_hpd) {
1180 if (blank && !pdev->externalDisplay->mBlanked) {
1181 pdev->externalDisplay->disable();
1182 }
1183 pdev->externalDisplay->mBlanked = !!blank;
1184 }
1185#else
1186 fence = pdev->externalDisplay->clearDisplay();
1187 if (fence >= 0)
1188 close(fence);
1189 pdev->externalDisplay->mBlanked = !!blank;
1190#endif
1191 break;
1192
1193 default:
1194 return -EINVAL;
1195
1196 }
1197
1198 return 0;
1199}
1200
1201int exynos5_close(hw_device_t* device);
1202
1203int exynos5_open(const struct hw_module_t *module, const char *name,
1204 struct hw_device_t **device)
1205{
1206 int ret = 0;
1207 int refreshRate;
5763fb39
T
1208
1209 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
1210 return -EINVAL;
1211 }
1212
1213 struct exynos5_hwc_composer_device_1_t *dev;
1214 dev = (struct exynos5_hwc_composer_device_1_t *)malloc(sizeof(*dev));
1215 memset(dev, 0, sizeof(*dev));
1216
1217 dev->primaryDisplay = new ExynosPrimaryDisplay(NUM_GSC_UNITS, dev);
1218 dev->externalDisplay = new ExynosExternalDisplayModule(dev);
1219#ifdef USES_VIRTUAL_DISPLAY
1220 dev->virtualDisplay = new ExynosVirtualDisplayModule(dev);
1221#endif
1222 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
1223 (const struct hw_module_t **)&dev->primaryDisplay->mGrallocModule)) {
1224 ALOGE("failed to get gralloc hw module");
1225 ret = -EINVAL;
1226 goto err_get_module;
1227 }
1228
1229 if (gralloc_open((const hw_module_t *)dev->primaryDisplay->mGrallocModule,
1230 &dev->primaryDisplay->mAllocDevice)) {
1231 ALOGE("failed to open gralloc");
1232 ret = -EINVAL;
1233 goto err_get_module;
1234 }
1235 dev->externalDisplay->mAllocDevice = dev->primaryDisplay->mAllocDevice;
1236#ifdef USES_VIRTUAL_DISPLAY
1237 dev->virtualDisplay->mAllocDevice = dev->primaryDisplay->mAllocDevice;
1238#endif
1239
1240 dev->primaryDisplay->mDisplayFd = open("/dev/graphics/fb0", O_RDWR);
1241 if (dev->primaryDisplay->mDisplayFd < 0) {
1242 ALOGE("failed to open framebuffer");
1243 ret = dev->primaryDisplay->mDisplayFd;
1244 goto err_open_fb;
1245 }
1246
1247 struct fb_var_screeninfo info;
1248 if (ioctl(dev->primaryDisplay->mDisplayFd, FBIOGET_VSCREENINFO, &info) == -1) {
1249 ALOGE("FBIOGET_VSCREENINFO ioctl failed: %s", strerror(errno));
1250 ret = -errno;
1251 goto err_ioctl;
1252 }
1253
1254 if (info.reserved[0] == 0 && info.reserved[1] == 0) {
1255 /* save physical lcd width, height to reserved[] */
1256 info.reserved[0] = info.xres;
1257 info.reserved[1] = info.yres;
1258
1259 if (ioctl(dev->primaryDisplay->mDisplayFd, FBIOPUT_VSCREENINFO, &info) == -1) {
1260 ALOGE("FBIOPUT_VSCREENINFO ioctl failed: %s", strerror(errno));
1261 ret = -errno;
1262 goto err_ioctl;
1263 }
1264 }
1265
1266 char value[PROPERTY_VALUE_MAX];
1267 property_get("debug.hwc.force_gpu", value, "0");
1268 dev->force_gpu = atoi(value);
1269
1270 /* restore physical lcd width, height from reserved[] */
1271 int lcd_xres, lcd_yres;
1272 lcd_xres = info.reserved[0];
1273 lcd_yres = info.reserved[1];
1274
1275 refreshRate = 1000000000000LLU /
1276 (
1277 uint64_t( info.upper_margin + info.lower_margin + lcd_yres + info.vsync_len )
1278 * ( info.left_margin + info.right_margin + lcd_xres + info.hsync_len )
1279 * info.pixclock
1280 );
1281
1282 if (refreshRate == 0) {
1283 ALOGW("invalid refresh rate, assuming 60 Hz");
1284 refreshRate = 60;
1285 }
1286
1287#if defined(USES_DUAL_DISPLAY)
1288 dev->primaryDisplay->mXres = 2 * lcd_xres;
1289#else
1290 dev->primaryDisplay->mXres = lcd_xres;
1291#endif
1292 dev->primaryDisplay->mYres = lcd_yres;
1293 dev->primaryDisplay->mXdpi = 1000 * (lcd_xres * 25.4f) / info.width;
1294 dev->primaryDisplay->mYdpi = 1000 * (lcd_yres * 25.4f) / info.height;
1295 dev->primaryDisplay->mVsyncPeriod = 1000000000 / refreshRate;
1296
1297 ALOGD("using\n"
1298 "xres = %d px\n"
1299 "yres = %d px\n"
1300 "width = %d mm (%f dpi)\n"
1301 "height = %d mm (%f dpi)\n"
1302 "refresh rate = %d Hz\n",
1303 dev->primaryDisplay->mXres, dev->primaryDisplay->mYres, info.width, dev->primaryDisplay->mXdpi / 1000.0,
1304 info.height, dev->primaryDisplay->mYdpi / 1000.0, refreshRate);
1305#ifndef USES_VPP
1306#ifdef FIMD_BW_OVERLAP_CHECK
1307 fimd_bw_overlap_limits_init(dev->primaryDisplay->mXres, dev->primaryDisplay->mYres,
1308 dev->primaryDisplay->mDmaChannelMaxBandwidth, dev->primaryDisplay->mDmaChannelMaxOverlapCount);
1309#else
1310 for (size_t i = 0; i < MAX_NUM_FIMD_DMA_CH; i++) {
1311 dev->primaryDisplay->mDmaChannelMaxBandwidth[i] =2560 * 1600;
1312 dev->primaryDisplay->mDmaChannelMaxOverlapCount[i] = 1;
1313 }
1314#endif
1315#endif
1316
1317#ifdef FIMD_WINDOW_OVERLAP_CHECK
1318 /*
1319 * Trivial implementation.
1320 * Effective only for checking the case that
1321 * mMaxWindowOverlapCnt = (NUM_HW_WINDOWS - 1)
1322 */
1323 dev->primaryDisplay->mMaxWindowOverlapCnt =
1324 fimd_window_overlap_limits_init(dev->primaryDisplay->mXres, dev->primaryDisplay->mYres);
1325#else
1326 dev->primaryDisplay->mMaxWindowOverlapCnt = NUM_HW_WINDOWS;
1327#endif
1328
1329 if (dev->externalDisplay->openHdmi() < 0) {
1330 ALOGE("openHdmi fail");
1331 }
1332
1333#if defined(USES_DUAL_DISPLAY)
1334 dev->secondaryDisplay = new ExynosSecondaryDisplayModule(dev);
1335 dev->secondaryDisplay->mAllocDevice = dev->primaryDisplay->mAllocDevice;
1336#endif
1337#ifdef USES_VPP
1338 dev->mDisplayResourceManager = new ExynosDisplayResourceManagerModule(dev);
1339#endif
1340 char devname[MAX_DEV_NAME + 1];
1341 devname[MAX_DEV_NAME] = '\0';
1342
1343 strncpy(devname, VSYNC_DEV_PREFIX, MAX_DEV_NAME);
1344 strlcat(devname, VSYNC_DEV_NAME, MAX_DEV_NAME);
1345
1346 dev->vsync_fd = open(devname, O_RDONLY);
1347 if (dev->vsync_fd < 0) {
1348 ALOGI("Failed to open vsync attribute at %s", devname);
1349 devname[strlen(VSYNC_DEV_PREFIX)] = '\0';
1350 strlcat(devname, VSYNC_DEV_MIDDLE, MAX_DEV_NAME);
1351 strlcat(devname, VSYNC_DEV_NAME, MAX_DEV_NAME);
1352 ALOGI("Retrying with %s", devname);
1353 dev->vsync_fd = open(devname, O_RDONLY);
1354 }
1355
1356#ifdef TRY_SECOND_VSYNC_DEV
1357 if (dev->vsync_fd < 0) {
1358 strncpy(devname, VSYNC_DEV_PREFIX, MAX_DEV_NAME);
1359 strlcat(devname, VSYNC_DEV_NAME2, MAX_DEV_NAME);
1360
1361 dev->vsync_fd = open(devname, O_RDONLY);
1362 if (dev->vsync_fd < 0) {
1363 ALOGI("Failed to open vsync attribute at %s", devname);
1364 devname[strlen(VSYNC_DEV_PREFIX)] = '\0';
1365 strlcat(devname, VSYNC_DEV_MIDDLE2, MAX_DEV_NAME);
1366 strlcat(devname, VSYNC_DEV_NAME2, MAX_DEV_NAME);
1367 ALOGI("Retrying with %s", devname);
1368 dev->vsync_fd = open(devname, O_RDONLY);
1369 }
1370 }
1371
1372#endif
1373
1374 if (dev->vsync_fd < 0) {
1375 ALOGE("failed to open vsync attribute");
1376 ret = dev->vsync_fd;
1377 goto err_hdmi_open;
1378 } else {
1379 struct stat st;
1380 if (fstat(dev->vsync_fd, &st) < 0) {
1381 ALOGE("Failed to stat vsync node at %s", devname);
1382 goto err_vsync_stat;
1383 }
1384
1385 if (!S_ISREG(st.st_mode)) {
1386 ALOGE("vsync node at %s should be a regualar file", devname);
1387 goto err_vsync_stat;
1388 }
1389 }
1390
1391 dev->psrInfoFd = NULL;
1392
1393 char psrDevname[MAX_DEV_NAME + 1];
1394 memset(psrDevname, 0, MAX_DEV_NAME + 1);
1395 strncpy(psrDevname, devname, strlen(devname) - 5);
1396 strlcat(psrDevname, "psr_info", MAX_DEV_NAME);
1397 ALOGI("PSR info devname = %s\n", psrDevname);
1398
1399 dev->psrInfoFd = fopen(psrDevname, "r");
1400 if (dev->psrInfoFd == NULL) {
1401 ALOGW("HWC needs to know whether LCD driver is using PSR mode or not\n");
1402 } else {
1403 char val[4];
1404 if (fread(&val, 1, 1, dev->psrInfoFd) == 1) {
1405 dev->psrMode = (0x03 & atoi(val));
1406 dev->panelType = ((0x03 << 2) & atoi(val)) >> 2;
1407 }
1408 }
1409
1410 ALOGI("PSR mode = %d (0: video mode, 1: DP PSR mode, 2: MIPI-DSI command mode)\n",
1411 dev->psrMode);
1412 ALOGI("Panel type = %d (0: Legacy, 1: DSC)\n",
1413 dev->panelType);
1414
1415#ifdef USES_VPP
1416 dev->primaryDisplay->mPanelType = dev->panelType;
1417 if (dev->panelType == PANEL_DSC) {
1418 uint32_t sliceNum = 0;
1419 uint32_t sliceSize = 0;
1420 if (fscanf(dev->psrInfoFd, "\n%d\n%d\n", &sliceNum, &sliceSize) < 0) {
1421 ALOGE("Fail to read slice information");
1422 } else {
1423 dev->primaryDisplay->mDSCHSliceNum = sliceNum;
1424 dev->primaryDisplay->mDSCYSliceSize = sliceSize;
1425 }
1426 ALOGI("DSC H_Slice_Num: %d, Y_Slice_Size: %d", dev->primaryDisplay->mDSCHSliceNum, dev->primaryDisplay->mDSCYSliceSize);
1427 }
1428#endif
1429
1430 dev->base.common.tag = HARDWARE_DEVICE_TAG;
1431 dev->base.common.version = HWC_VERSION;
1432 dev->base.common.module = const_cast<hw_module_t *>(module);
1433 dev->base.common.close = exynos5_close;
1434
1435 dev->base.prepare = exynos5_prepare;
1436 dev->base.set = exynos5_set;
1437 dev->base.eventControl = exynos5_eventControl;
1438 dev->base.query = exynos5_query;
1439 dev->base.registerProcs = exynos5_registerProcs;
1440 dev->base.dump = exynos5_dump;
1441 dev->base.getDisplayConfigs = exynos5_getDisplayConfigs;
1442 dev->base.getDisplayAttributes = exynos5_getDisplayAttributes;
1443 if (hwcHasApiVersion((hwc_composer_device_1_t*)dev, HWC_DEVICE_API_VERSION_1_4)) {
1444 dev->base.getActiveConfig = exynos_getActiveConfig;
1445 dev->base.setActiveConfig = exynos_setActiveConfig;
1446 dev->base.setCursorPositionAsync = exynos_setCursorPositionAsync;
1447 dev->base.setPowerMode = exynos_setPowerMode;
1448 } else {
1449 dev->base.blank = exynos5_blank;
1450 }
1451
1452 *device = &dev->base.common;
1453
1454#ifdef IP_SERVICE
1455 android::ExynosIPService *mIPService;
1456 mIPService = android::ExynosIPService::getExynosIPService();
1457 ret = mIPService->createServiceLocked();
1458 if (ret < 0)
1459 goto err_vsync;
1460#endif
1461
1462#ifdef HWC_SERVICES
1463 android::ExynosHWCService *mHWCService;
1464 mHWCService = android::ExynosHWCService::getExynosHWCService();
1465 mHWCService->setExynosHWCCtx(dev);
1466 mHWCService->setPSRExitCallback(doPSRExit);
1467#if !defined(HDMI_INCAPABLE)
1468 mHWCService->setBootFinishedCallback(exynos5_boot_finished);
1469#endif
1470#endif
1471
1472 dev->mHdmiResolutionChanged = false;
1473 dev->mHdmiResolutionHandled = true;
1474 dev->mS3DMode = S3D_MODE_DISABLED;
1475 dev->mHdmiPreset = HDMI_PRESET_DEFAULT;
1476 dev->mHdmiCurrentPreset = HDMI_PRESET_DEFAULT;
1477 dev->mUseSubtitles = false;
1478 dev->notifyPSRExit = false;
1479
1480#if defined(USES_CEC)
1481 if (dev->hdmi_hpd)
1482 start_cec(dev);
1483 else
1484 dev->mCecFd = -1;
1485#endif
1486
1487 ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev);
1488 if (ret) {
1489 ALOGE("failed to start vsync thread: %s", strerror(ret));
1490 ret = -ret;
1491 goto err_vsync;
1492 }
1493
1494#ifdef G2D_COMPOSITION
1495 dev->primaryDisplay->num_of_allocated_lay = 0;
1496#endif
1497
1498 dev->allowOTF = true;
1499
1500 dev->hwc_ctrl.max_num_ovly = NUM_HW_WINDOWS;
1501 dev->hwc_ctrl.num_of_video_ovly = 2;
1502 dev->hwc_ctrl.dynamic_recomp_mode = (dev->psrMode == PSR_NONE);
1503 dev->hwc_ctrl.skip_static_layer_mode = true;
1504 dev->hwc_ctrl.dma_bw_balance_mode = true;
1505
1506 hwcDebug = 0;
1507
1508 if (dev->hwc_ctrl.dynamic_recomp_mode == true)
1509 exynos5_create_update_stat_thread(dev);
1510
1511 return 0;
1512
1513err_vsync:
1514 if (dev->psrInfoFd != NULL)
1515 fclose(dev->psrInfoFd);
1516err_vsync_stat:
1517 close(dev->vsync_fd);
1518err_hdmi_open:
1519 if (dev->externalDisplay->mDisplayFd > 0)
1520 close(dev->externalDisplay->mDisplayFd);
1521err_ioctl:
1522 close(dev->primaryDisplay->mDisplayFd);
1523#if defined(USES_DUAL_DISPLAY)
1524 if (dev->secondaryDisplay->mDisplayFd > 0)
1525 close(dev->secondaryDisplay->mDisplayFd);
1526#endif
1527err_open_fb:
1528 gralloc_close(dev->primaryDisplay->mAllocDevice);
1529err_get_module:
1530 free(dev);
1531 return ret;
1532}
1533
1534int exynos5_close(hw_device_t *device)
1535{
1536 struct exynos5_hwc_composer_device_1_t *dev =
1537 (struct exynos5_hwc_composer_device_1_t *)device;
1538 pthread_kill(dev->vsync_thread, SIGTERM);
1539 pthread_join(dev->vsync_thread, NULL);
1540 if (pthread_kill(dev->update_stat_thread, 0) != ESRCH) {
1541 pthread_kill(dev->update_stat_thread, SIGTERM);
1542 pthread_join(dev->update_stat_thread, NULL);
1543 }
1544#ifndef USES_VPP
1545 for (size_t i = 0; i < NUM_GSC_UNITS; i++)
1546 dev->primaryDisplay->mMPPs[i]->cleanupM2M();
1547#endif
1548 gralloc_close(dev->primaryDisplay->mAllocDevice);
1549 close(dev->vsync_fd);
1550
1551#ifdef USE_FB_PHY_LINEAR
1552#ifdef G2D_COMPOSITION
1553 for (int i = 0; i < NUM_HW_WIN_FB_PHY; i++) {
1554 for (int j = 0; j < NUM_GSC_DST_BUFS; j++) {
1555 if (dev->win_buf_vir_addr[i][j]) {
1556 ion_unmap((void *)dev->win_buf_vir_addr[i][j], dev->win_buf_map_size[i]);
1557 dev->win_buf_vir_addr[i][j] = 0;
1558 }
1559 }
1560 }
1561#endif
1562
1563 for (int i = 0; i < NUM_HW_WIN_FB_PHY; i++) {
1564 for (int j = 0; j < NUM_GSC_DST_BUFS; j++) {
1565 if (dev->win_buf[i][j]) {
1566 dev->primaryDisplay->mAllocDevice->free(dev->primaryDisplay->mAllocDevice, dev->win_buf[i][j]);
1567 dev->win_buf[i][j] = NULL;
1568 }
1569 }
1570 }
1571#endif
1572
1573#ifdef USES_VPP
1574 delete dev->mDisplayResourceManager;
1575#endif
1576
1577 return 0;
1578}
1579
1580static struct hw_module_methods_t exynos5_hwc_module_methods = {
55264519 1581 .open = exynos5_open,
5763fb39
T
1582};
1583
1584hwc_module_t HAL_MODULE_INFO_SYM = {
55264519
JA
1585 .common = {
1586 .tag = HARDWARE_MODULE_TAG,
1587 .module_api_version = HWC_MODULE_API_VERSION_0_1,
1588 .hal_api_version = HARDWARE_HAL_API_VERSION,
1589 .id = HWC_HARDWARE_MODULE_ID,
1590 .name = "Samsung exynos5 hwcomposer module",
1591 .author = "Samsung LSI",
1592 .methods = &exynos5_hwc_module_methods,
1593 .dso = 0,
1594 .reserved = {0},
5763fb39
T
1595 }
1596};