Commit | Line | Data |
---|---|---|
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" | |
30 | namespace android { | |
31 | class 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 | ||
52 | void 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) | |
63 | void 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 | ||
178 | void 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 | ||
199 | void 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 | ||
234 | int 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 | ||
333 | int 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 | ||
430 | void 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 | ||
438 | int 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 | ||
459 | int 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 | ||
480 | void 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 |
525 | void 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 | ||
562 | void 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 | ||
587 | void *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 | ||
612 | void 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 | ||
623 | void *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 | ||
705 | int 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 | ||
812 | void 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 | ||
882 | int 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 | ||
937 | int32_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 | ||
960 | int 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 | ||
995 | int 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 | ||
1019 | int 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 | 1053 | int 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 | ||
1058 | int 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 | ||
1201 | int exynos5_close(hw_device_t* device); | |
1202 | ||
1203 | int 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 | ||
1513 | err_vsync: | |
1514 | if (dev->psrInfoFd != NULL) | |
1515 | fclose(dev->psrInfoFd); | |
1516 | err_vsync_stat: | |
1517 | close(dev->vsync_fd); | |
1518 | err_hdmi_open: | |
1519 | if (dev->externalDisplay->mDisplayFd > 0) | |
1520 | close(dev->externalDisplay->mDisplayFd); | |
1521 | err_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 | |
1527 | err_open_fb: | |
1528 | gralloc_close(dev->primaryDisplay->mAllocDevice); | |
1529 | err_get_module: | |
1530 | free(dev); | |
1531 | return ret; | |
1532 | } | |
1533 | ||
1534 | int 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 | ||
1580 | static struct hw_module_methods_t exynos5_hwc_module_methods = { | |
55264519 | 1581 | .open = exynos5_open, |
5763fb39 T |
1582 | }; |
1583 | ||
1584 | hwc_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 | }; |