blob: c59fe907cdeecdc8e3e5b93f9abbc89307833cb0 [file] [log] [blame]
Ethan Yonkerfbb43532015-12-28 21:54:50 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdbool.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21#include <errno.h>
22
23#include <fcntl.h>
24#include <stdio.h>
25
26#include <sys/cdefs.h>
27#include <sys/ioctl.h>
28#include <sys/mman.h>
29#include <sys/types.h>
30
31#include <linux/fb.h>
32#include <linux/kd.h>
33
34#ifdef MSM_BSP
35#include <linux/msm_mdp.h>
36#include <linux/msm_ion.h>
37#endif
38
39#include "minui.h"
40#include "graphics.h"
41#include <pixelflinger/pixelflinger.h>
42
43#define MDP_V4_0 400
44#define MAX_DISPLAY_DIM 2048
45
46static GRSurface* overlay_init(minui_backend*);
47static GRSurface* overlay_flip(minui_backend*);
48static void overlay_blank(minui_backend*, bool);
49static void overlay_exit(minui_backend*);
50
51static GRSurface gr_framebuffer;
52static GRSurface* gr_draw = NULL;
53static int displayed_buffer;
54
55static fb_var_screeninfo vi;
56static int fb_fd = -1;
57static bool isMDP5 = false;
58static int leftSplit = 0;
59static int rightSplit = 0;
60#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
61
62static size_t frame_size = 0;
63
64#ifdef MSM_BSP
65typedef struct {
66 unsigned char *mem_buf;
67 int size;
68 int ion_fd;
69 int mem_fd;
70 struct ion_handle_data handle_data;
71} memInfo;
72
73//Left and right overlay id
74static int overlayL_id = MSMFB_NEW_REQUEST;
75static int overlayR_id = MSMFB_NEW_REQUEST;
76
77static memInfo mem_info;
78
79static int map_mdp_pixel_format()
80{
81 if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGB_565)
82 return MDP_RGB_565;
83 else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_BGRA_8888)
84 return MDP_BGRA_8888;
85 else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGBA_8888)
86 return MDP_RGBA_8888;
87 else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGBX_8888)
88 return MDP_RGBA_8888;
89 printf("No known pixel format for map_mdp_pixel_format, defaulting to MDP_RGB_565.\n");
90 return MDP_RGB_565;
91}
92#endif // MSM_BSP
93
94static minui_backend my_backend = {
95 .init = overlay_init,
96 .flip = overlay_flip,
97 .blank = overlay_blank,
98 .exit = overlay_exit,
99};
100
101bool target_has_overlay(char *version)
102{
103 int ret;
104 int mdp_version;
105 bool overlay_supported = false;
106
107 if (strlen(version) >= 8) {
108 if(!strncmp(version, "msmfb", strlen("msmfb"))) {
109 char str_ver[4];
110 memcpy(str_ver, version + strlen("msmfb"), 3);
111 str_ver[3] = '\0';
112 mdp_version = atoi(str_ver);
113 if (mdp_version >= MDP_V4_0) {
114 overlay_supported = true;
115 }
116 } else if (!strncmp(version, "mdssfb", strlen("mdssfb"))) {
117 overlay_supported = true;
118 isMDP5 = true;
119 }
120 }
121
122 return overlay_supported;
123}
124
125minui_backend* open_overlay() {
126 fb_fix_screeninfo fi;
127 int fd;
128
129 fd = open("/dev/graphics/fb0", O_RDWR);
130 if (fd < 0) {
131 perror("open_overlay cannot open fb0");
132 return NULL;
133 }
134
135 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
136 perror("failed to get fb0 info");
137 close(fd);
138 return NULL;
139 }
140
141 if (target_has_overlay(fi.id)) {
142#ifdef MSM_BSP
143 close(fd);
144 return &my_backend;
145#else
146 printf("Overlay graphics may work (%s), but not enabled. Use TW_TARGET_USES_QCOM_BSP := true to enable.\n", fi.id);
147#endif
148 }
149 close(fd);
150 return NULL;
151}
152
153static void overlay_blank(minui_backend* backend __unused, bool blank)
154{
155#if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS)
156 int fd;
157 char brightness[4];
158 snprintf(brightness, 4, "%03d", TW_MAX_BRIGHTNESS/2);
159
160 fd = open(TW_BRIGHTNESS_PATH, O_RDWR);
161 if (fd < 0) {
162 perror("cannot open LCD backlight");
163 return;
164 }
165 write(fd, blank ? "000" : brightness, 3);
166 close(fd);
167#else
168 int ret;
169
170 ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
171 if (ret < 0)
172 perror("ioctl(): blank");
173#endif
174}
175
176#ifdef MSM_BSP
177void setDisplaySplit(void) {
178 char split[64] = {0};
179 if (!isMDP5)
180 return;
181 FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
182 if (fp) {
183 //Format "left right" space as delimiter
184 if(fread(split, sizeof(char), 64, fp)) {
185 leftSplit = atoi(split);
186 printf("Left Split=%d\n",leftSplit);
187 char *rght = strpbrk(split, " ");
188 if (rght)
189 rightSplit = atoi(rght + 1);
190 printf("Right Split=%d\n", rightSplit);
191 }
192 } else {
193 printf("Failed to open mdss_fb_split node\n");
194 }
195 if (fp)
196 fclose(fp);
197}
198
199int getLeftSplit(void) {
200 //Default even split for all displays with high res
201 int lSplit = vi.xres / 2;
202
203 //Override if split published by driver
204 if (leftSplit)
205 lSplit = leftSplit;
206
207 return lSplit;
208}
209
210int getRightSplit(void) {
211 return rightSplit;
212}
213
214int free_ion_mem(void) {
215 int ret = 0;
216
217 if (mem_info.mem_buf)
218 munmap(mem_info.mem_buf, mem_info.size);
219
220 if (mem_info.ion_fd >= 0) {
221 ret = ioctl(mem_info.ion_fd, ION_IOC_FREE, &mem_info.handle_data);
222 if (ret < 0)
223 perror("free_mem failed ");
224 }
225
226 if (mem_info.mem_fd >= 0)
227 close(mem_info.mem_fd);
228 if (mem_info.ion_fd >= 0)
229 close(mem_info.ion_fd);
230
231 memset(&mem_info, 0, sizeof(mem_info));
232 mem_info.mem_fd = -1;
233 mem_info.ion_fd = -1;
234 return 0;
235}
236
237int alloc_ion_mem(unsigned int size)
238{
239 int result;
240 struct ion_fd_data fd_data;
241 struct ion_allocation_data ionAllocData;
242
243 mem_info.ion_fd = open("/dev/ion", O_RDWR|O_DSYNC);
244 if (mem_info.ion_fd < 0) {
245 perror("ERROR: Can't open ion ");
246 return -errno;
247 }
248
249 ionAllocData.flags = 0;
250 ionAllocData.len = size;
251 ionAllocData.align = sysconf(_SC_PAGESIZE);
252#ifdef NEW_ION_HEAP
253 ionAllocData.heap_id_mask =
254#else
255 ionAllocData.heap_mask =
256#endif
257 ION_HEAP(ION_IOMMU_HEAP_ID) |
258 ION_HEAP(ION_SYSTEM_CONTIG_HEAP_ID);
259
260 result = ioctl(mem_info.ion_fd, ION_IOC_ALLOC, &ionAllocData);
261 if(result){
262 perror("ION_IOC_ALLOC Failed ");
263 close(mem_info.ion_fd);
264 return result;
265 }
266
267 fd_data.handle = ionAllocData.handle;
268 mem_info.handle_data.handle = ionAllocData.handle;
269 result = ioctl(mem_info.ion_fd, ION_IOC_MAP, &fd_data);
270 if (result) {
271 perror("ION_IOC_MAP Failed ");
272 free_ion_mem();
273 return result;
274 }
275 mem_info.mem_buf = (unsigned char *)mmap(NULL, size, PROT_READ |
276 PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
277 mem_info.mem_fd = fd_data.fd;
278
279 if (!mem_info.mem_buf) {
280 perror("ERROR: mem_buf MAP_FAILED ");
281 free_ion_mem();
282 return -ENOMEM;
283 }
284
285 return 0;
286}
287
288bool isDisplaySplit(void) {
289 if (vi.xres > MAX_DISPLAY_DIM)
290 return true;
291 //check if right split is set by driver
292 if (getRightSplit())
293 return true;
294
295 return false;
296}
297
298int allocate_overlay(int fd, GRSurface gr_fb)
299{
300 int ret = 0;
301
302 if (!isDisplaySplit()) {
303 // Check if overlay is already allocated
304 if (MSMFB_NEW_REQUEST == overlayL_id) {
305 struct mdp_overlay overlayL;
306
307 memset(&overlayL, 0 , sizeof (struct mdp_overlay));
308
309 /* Fill Overlay Data */
310 overlayL.src.width = ALIGN(gr_fb.width, 32);
311 overlayL.src.height = gr_fb.height;
312 overlayL.src.format = map_mdp_pixel_format();
313 overlayL.src_rect.w = gr_fb.width;
314 overlayL.src_rect.h = gr_fb.height;
315 overlayL.dst_rect.w = gr_fb.width;
316 overlayL.dst_rect.h = gr_fb.height;
317 overlayL.alpha = 0xFF;
318 overlayL.transp_mask = MDP_TRANSP_NOP;
319 overlayL.id = MSMFB_NEW_REQUEST;
320 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL);
321 if (ret < 0) {
322 perror("Overlay Set Failed");
323 return ret;
324 }
325 overlayL_id = overlayL.id;
326 }
327 } else {
328 float xres = vi.xres;
329 int lSplit = getLeftSplit();
330 float lSplitRatio = lSplit / xres;
331 float lCropWidth = gr_fb.width * lSplitRatio;
332 int lWidth = lSplit;
333 int rWidth = gr_fb.width - lSplit;
334 int height = gr_fb.height;
335
336 if (MSMFB_NEW_REQUEST == overlayL_id) {
337
338 struct mdp_overlay overlayL;
339
340 memset(&overlayL, 0 , sizeof (struct mdp_overlay));
341
342 /* Fill OverlayL Data */
343 overlayL.src.width = ALIGN(gr_fb.width, 32);
344 overlayL.src.height = gr_fb.height;
345 overlayL.src.format = map_mdp_pixel_format();
346 overlayL.src_rect.x = 0;
347 overlayL.src_rect.y = 0;
348 overlayL.src_rect.w = lCropWidth;
349 overlayL.src_rect.h = gr_fb.height;
350 overlayL.dst_rect.x = 0;
351 overlayL.dst_rect.y = 0;
352 overlayL.dst_rect.w = lWidth;
353 overlayL.dst_rect.h = height;
354 overlayL.alpha = 0xFF;
355 overlayL.transp_mask = MDP_TRANSP_NOP;
356 overlayL.id = MSMFB_NEW_REQUEST;
357 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL);
358 if (ret < 0) {
359 perror("OverlayL Set Failed");
360 return ret;
361 }
362 overlayL_id = overlayL.id;
363 }
364 if (MSMFB_NEW_REQUEST == overlayR_id) {
365 struct mdp_overlay overlayR;
366
367 memset(&overlayR, 0 , sizeof (struct mdp_overlay));
368
369 /* Fill OverlayR Data */
370 overlayR.src.width = ALIGN(gr_fb.width, 32);
371 overlayR.src.height = gr_fb.height;
372 overlayR.src.format = map_mdp_pixel_format();
373 overlayR.src_rect.x = lCropWidth;
374 overlayR.src_rect.y = 0;
375 overlayR.src_rect.w = gr_fb.width - lCropWidth;
376 overlayR.src_rect.h = gr_fb.height;
377 overlayR.dst_rect.x = 0;
378 overlayR.dst_rect.y = 0;
379 overlayR.dst_rect.w = rWidth;
380 overlayR.dst_rect.h = height;
381 overlayR.alpha = 0xFF;
382 overlayR.flags = MDSS_MDP_RIGHT_MIXER;
383 overlayR.transp_mask = MDP_TRANSP_NOP;
384 overlayR.id = MSMFB_NEW_REQUEST;
385 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayR);
386 if (ret < 0) {
387 perror("OverlayR Set Failed");
388 return ret;
389 }
390 overlayR_id = overlayR.id;
391 }
392
393 }
394 return 0;
395}
396
397int overlay_display_frame(int fd, void* data, size_t size)
398{
399 int ret = 0;
400 struct msmfb_overlay_data ovdataL, ovdataR;
401 struct mdp_display_commit ext_commit;
402
403 if (!isDisplaySplit()) {
404 if (overlayL_id == MSMFB_NEW_REQUEST) {
405 perror("display_frame failed, no overlay\n");
406 return -EINVAL;
407 }
408
409 memcpy(mem_info.mem_buf, data, size);
410
411 memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data));
412
413 ovdataL.id = overlayL_id;
414 ovdataL.data.flags = 0;
415 ovdataL.data.offset = 0;
416 ovdataL.data.memory_id = mem_info.mem_fd;
417 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL);
418 if (ret < 0) {
419 perror("overlay_display_frame failed, overlay play Failed\n");
420 printf("%i, %i, %i, %i\n", ret, fb_fd, fd, errno);
421 return ret;
422 }
423 } else {
424
425 if (overlayL_id == MSMFB_NEW_REQUEST) {
426 perror("display_frame failed, no overlayL \n");
427 return -EINVAL;
428 }
429
430 memcpy(mem_info.mem_buf, data, size);
431
432 memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data));
433
434 ovdataL.id = overlayL_id;
435 ovdataL.data.flags = 0;
436 ovdataL.data.offset = 0;
437 ovdataL.data.memory_id = mem_info.mem_fd;
438 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL);
439 if (ret < 0) {
440 perror("overlay_display_frame failed, overlayL play Failed\n");
441 return ret;
442 }
443
444 if (overlayR_id == MSMFB_NEW_REQUEST) {
445 perror("display_frame failed, no overlayR \n");
446 return -EINVAL;
447 }
448 memset(&ovdataR, 0, sizeof(struct msmfb_overlay_data));
449
450 ovdataR.id = overlayR_id;
451 ovdataR.data.flags = 0;
452 ovdataR.data.offset = 0;
453 ovdataR.data.memory_id = mem_info.mem_fd;
454 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataR);
455 if (ret < 0) {
456 perror("overlay_display_frame failed, overlayR play Failed\n");
457 return ret;
458 }
459 }
460 memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
461 ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
462 ext_commit.wait_for_finish = 1;
463 ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit);
464 if (ret < 0) {
465 perror("overlay_display_frame failed, overlay commit Failed\n!");
466 }
467
468 return ret;
469}
470
471static GRSurface* overlay_flip(minui_backend* backend __unused) {
472#if defined(RECOVERY_BGRA)
473 // In case of BGRA, do some byte swapping
474 unsigned int idx;
475 unsigned char tmp;
476 unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data;
477 for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes);
478 idx += 4) {
479 tmp = ucfb_vaddr[idx];
480 ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2];
481 ucfb_vaddr[idx + 2] = tmp;
482 }
483#endif
484 // Copy from the in-memory surface to the framebuffer.
485 overlay_display_frame(fb_fd, gr_draw->data, frame_size);
486 return gr_draw;
487}
488
489int free_overlay(int fd)
490{
491 int ret = 0;
492 struct mdp_display_commit ext_commit;
493
494 if (!isDisplaySplit()) {
495 if (overlayL_id != MSMFB_NEW_REQUEST) {
496 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id);
497 if (ret) {
498 perror("Overlay Unset Failed");
499 overlayL_id = MSMFB_NEW_REQUEST;
500 return ret;
501 }
502 }
503 } else {
504
505 if (overlayL_id != MSMFB_NEW_REQUEST) {
506 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id);
507 if (ret) {
508 perror("OverlayL Unset Failed");
509 }
510 }
511
512 if (overlayR_id != MSMFB_NEW_REQUEST) {
513 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayR_id);
514 if (ret) {
515 perror("OverlayR Unset Failed");
516 overlayR_id = MSMFB_NEW_REQUEST;
517 return ret;
518 }
519 }
520 }
521 memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
522 ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
523 ext_commit.wait_for_finish = 1;
524 ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit);
525 if (ret < 0) {
526 perror("ERROR: Clear MSMFB_DISPLAY_COMMIT failed!");
527 overlayL_id = MSMFB_NEW_REQUEST;
528 overlayR_id = MSMFB_NEW_REQUEST;
529 return ret;
530 }
531 overlayL_id = MSMFB_NEW_REQUEST;
532 overlayR_id = MSMFB_NEW_REQUEST;
533
534 return 0;
535}
536
537static GRSurface* overlay_init(minui_backend* backend) {
538 int fd = open("/dev/graphics/fb0", O_RDWR);
539 if (fd == -1) {
540 perror("cannot open fb0");
541 return NULL;
542 }
543
544 fb_fix_screeninfo fi;
545 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
546 perror("failed to get fb0 info");
547 close(fd);
548 return NULL;
549 }
550
551 if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
552 perror("failed to get fb0 info");
553 close(fd);
554 return NULL;
555 }
556
557 // We print this out for informational purposes only, but
558 // throughout we assume that the framebuffer device uses an RGBX
559 // pixel format. This is the case for every development device I
560 // have access to. For some of those devices (eg, hammerhead aka
561 // Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
562 // different format (XBGR) but actually produces the correct
563 // results on the display when you write RGBX.
564 //
565 // If you have a device that actually *needs* another pixel format
566 // (ie, BGRX, or 565), patches welcome...
567
568 printf("fb0 reports (possibly inaccurate):\n"
569 " vi.bits_per_pixel = %d\n"
570 " vi.red.offset = %3d .length = %3d\n"
571 " vi.green.offset = %3d .length = %3d\n"
572 " vi.blue.offset = %3d .length = %3d\n",
573 vi.bits_per_pixel,
574 vi.red.offset, vi.red.length,
575 vi.green.offset, vi.green.length,
576 vi.blue.offset, vi.blue.length);
577
578 gr_framebuffer.width = vi.xres;
579 gr_framebuffer.height = vi.yres;
580 gr_framebuffer.row_bytes = fi.line_length;
581 gr_framebuffer.pixel_bytes = vi.bits_per_pixel / 8;
582 //gr_framebuffer.data = reinterpret_cast<uint8_t*>(bits);
583 if (vi.bits_per_pixel == 16) {
584 printf("setting GGL_PIXEL_FORMAT_RGB_565\n");
585 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGB_565;
Ziyan4fea38a2016-01-28 01:19:35 +0100586 } else if (vi.red.offset == 8 || vi.red.offset == 16) {
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100587 printf("setting GGL_PIXEL_FORMAT_BGRA_8888\n");
588 gr_framebuffer.format = GGL_PIXEL_FORMAT_BGRA_8888;
589 } else if (vi.red.offset == 0) {
590 printf("setting GGL_PIXEL_FORMAT_RGBA_8888\n");
591 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBA_8888;
592 } else if (vi.red.offset == 24) {
593 printf("setting GGL_PIXEL_FORMAT_RGBX_8888\n");
594 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBX_8888;
595 } else {
596 if (vi.red.length == 8) {
597 printf("No valid pixel format detected, trying GGL_PIXEL_FORMAT_RGBX_8888\n");
598 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBX_8888;
599 } else {
600 printf("No valid pixel format detected, trying GGL_PIXEL_FORMAT_RGB_565\n");
601 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGB_565;
602 }
603 }
604
605 frame_size = fi.line_length * vi.yres;
606
607 gr_framebuffer.data = reinterpret_cast<uint8_t*>(calloc(frame_size, 1));
608 if (gr_framebuffer.data == NULL) {
609 perror("failed to calloc framebuffer");
610 close(fd);
611 return NULL;
612 }
613
614 gr_draw = &gr_framebuffer;
615 fb_fd = fd;
616
617 printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height);
618
619 overlay_blank(backend, true);
620 overlay_blank(backend, false);
621
622 if (!alloc_ion_mem(frame_size))
623 allocate_overlay(fb_fd, gr_framebuffer);
624
625 return gr_draw;
626}
627
628static void overlay_exit(minui_backend* backend __unused) {
629 free_overlay(fb_fd);
630 free_ion_mem();
631
632 close(fb_fd);
633 fb_fd = -1;
634
635 if (gr_draw) {
636 free(gr_draw->data);
637 free(gr_draw);
638 }
639 gr_draw = NULL;
640}
641#else // MSM_BSP
642static GRSurface* overlay_flip(minui_backend* backend __unused) {
643 return NULL;
644}
645
646static GRSurface* overlay_init(minui_backend* backend __unused) {
647 return NULL;
648}
649
650static void overlay_exit(minui_backend* backend __unused) {
651 return;
652}
653#endif // MSM_BSP