OSDN Git Service

support hdmi clone more for intel GEN8+ gpus
[android-x86/external-drm_gralloc.git] / gralloc_drm_kms.c
1 /*
2  * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3  * Copyright (C) 2010-2011 LunarG Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23
24 #define LOG_TAG "GRALLOC-KMS"
25
26 #include <cutils/properties.h>
27 #include <cutils/log.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <signal.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <poll.h>
34 #include <math.h>
35 #include "gralloc_drm.h"
36 #include "gralloc_drm_priv.h"
37 #include <hardware_legacy/uevent.h>
38
39 #include <drm_fourcc.h>
40
41 /*
42  * Return true if a bo needs fb.
43  */
44 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
45 {
46         return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
47                 bo->drm->swap_mode != DRM_SWAP_COPY);
48 }
49
50 static unsigned int drm_format_from_hal(int hal_format)
51 {
52         switch(hal_format) {
53                 case HAL_PIXEL_FORMAT_RGB_888:
54                 case HAL_PIXEL_FORMAT_BGRA_8888:
55                         return DRM_FORMAT_XRGB8888;
56                 case HAL_PIXEL_FORMAT_RGBX_8888:
57                         return DRM_FORMAT_XBGR8888;
58                 case HAL_PIXEL_FORMAT_RGBA_8888:
59                         return DRM_FORMAT_RGBA8888;
60                 case HAL_PIXEL_FORMAT_RGB_565:
61                         return DRM_FORMAT_RGB565;
62                 case HAL_PIXEL_FORMAT_YV12:
63                         return DRM_FORMAT_YUV420;
64                 case HAL_PIXEL_FORMAT_DRM_NV12:
65                         return DRM_FORMAT_NV12;
66                 default:
67                         return 0;
68         }
69 }
70
71 /*
72  * Modify pitches, offsets and handles according to
73  * the format and return corresponding drm format value
74  */
75 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
76         uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
77 {
78         struct gralloc_drm_t *drm = bo->drm;
79
80         pitches[0] = bo->handle->stride;
81         handles[0] = bo->fb_handle;
82
83         /* driver takes care of HW specific padding, alignment etc. */
84         if (drm->drv->resolve_format)
85                 drm->drv->resolve_format(drm->drv, bo,
86                         pitches, offsets, handles);
87
88         return drm_format_from_hal(bo->handle->format);
89 }
90
91 /*
92  * Returns planes that are supported for a particular format
93  */
94 unsigned int planes_for_format(struct gralloc_drm_t *drm,
95         int hal_format)
96 {
97         unsigned int i, j, mask = 0;
98         unsigned int drm_format = drm_format_from_hal(hal_format);
99         struct gralloc_drm_plane_t *plane = drm->planes;
100
101         /* no planes available */
102         if (!plane)
103                 return 0;
104
105         /* iterate through planes, mark those that match format */
106         for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
107                 for (j=0; j<plane->drm_plane->count_formats; j++)
108                         if (plane->drm_plane->formats[j] == drm_format)
109                                 mask |= (1U << plane->drm_plane->plane_id);
110
111         return mask;
112 }
113
114 /*
115  * Add a fb object for a bo.
116  */
117 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
118 {
119         uint32_t pitches[4] = { 0, 0, 0, 0 };
120         uint32_t offsets[4] = { 0, 0, 0, 0 };
121         uint32_t handles[4] = { 0, 0, 0, 0 };
122
123         if (bo->fb_id)
124                 return 0;
125
126         int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
127
128         if (drm_format == 0) {
129                 ALOGE("error resolving drm format");
130                 return -EINVAL;
131         }
132
133         return drmModeAddFB2(bo->drm->fd,
134                 bo->handle->width, bo->handle->height,
135                 drm_format, handles, pitches, offsets,
136                 (uint32_t *) &bo->fb_id, 0);
137 }
138
139 /*
140  * Remove a fb object for a bo.
141  */
142 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
143 {
144         if (bo->fb_id) {
145                 drmModeRmFB(bo->drm->fd, bo->fb_id);
146                 bo->fb_id = 0;
147         }
148 }
149
150 /*
151  * Program CRTC.
152  */
153 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
154         struct gralloc_drm_output *output, int fb_id)
155 {
156         int ret;
157
158         ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
159                         0, 0, &output->connector_id, 1, &output->mode);
160         if (ret) {
161                 ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
162                         strerror(errno), output->crtc_id, fb_id, output->connector_id,
163                         output->mode.hdisplay, output->mode.vdisplay);
164                 return ret;
165         }
166
167         if (drm->mode_quirk_vmwgfx)
168                 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
169
170         return ret;
171 }
172
173 /*
174  * Callback for a page flip event.
175  */
176 static void page_flip_handler(int fd, unsigned int sequence,
177                 unsigned int tv_sec, unsigned int tv_usec,
178                 void *user_data)
179 {
180         struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
181
182         /* ack the last scheduled flip */
183         drm->current_front = drm->next_front;
184         drm->next_front = NULL;
185 }
186
187 /*
188  * Set a plane.
189  */
190 static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
191         struct gralloc_drm_plane_t *plane)
192 {
193         struct gralloc_drm_bo_t *bo = NULL;
194         int err;
195
196         if (plane->handle)
197                 bo = gralloc_drm_bo_from_handle(plane->handle);
198
199         // create a framebuffer if does not exist
200         if (bo && bo->fb_id == 0) {
201                 err = gralloc_drm_bo_add_fb(bo);
202                 if (err) {
203                         ALOGE("%s: could not create drm fb, (%s)",
204                                 __func__, strerror(-err));
205                         return err;
206                 }
207         }
208
209         err = drmModeSetPlane(drm->fd,
210                 plane->drm_plane->plane_id,
211                 drm->primary.crtc_id,
212                 bo ? bo->fb_id : 0,
213                 0, // flags
214                 plane->dst_x,
215                 plane->dst_y,
216                 plane->dst_w,
217                 plane->dst_h,
218                 plane->src_x << 16,
219                 plane->src_y << 16,
220                 plane->src_w << 16,
221                 plane->src_h << 16);
222
223         if (err) {
224                 /* clear plane_mask so that this buffer won't be tried again */
225                 struct gralloc_drm_handle_t *drm_handle =
226                         (struct gralloc_drm_handle_t *) plane->handle;
227                 drm_handle->plane_mask = 0;
228
229                 ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
230                         strerror(-err),
231                         plane->drm_plane->plane_id,
232                         drm->primary.crtc_id,
233                         bo ? bo->fb_id : 0);
234         }
235
236         if (plane->prev)
237                 gralloc_drm_bo_decref(plane->prev);
238
239         if (bo)
240                 bo->refcount++;
241
242         plane->prev = bo;
243
244         return err;
245 }
246
247 /*
248  * Returns if a particular plane is supported with the implementation
249  */
250 static unsigned is_plane_supported(const struct gralloc_drm_t *drm,
251         const struct gralloc_drm_plane_t *plane)
252 {
253         /* Planes are only supported on primary pipe for now */
254         return plane->drm_plane->possible_crtcs & (1 << drm->primary.pipe);
255 }
256
257 /*
258  * Sets all the active planes to be displayed.
259  */
260 static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
261 {
262         struct gralloc_drm_plane_t *plane = drm->planes;
263         unsigned int i;
264         for (i = 0; i < drm->plane_resources->count_planes;
265                 i++, plane++) {
266                 /* plane is not in use at all */
267                 if (!plane->active && !plane->handle)
268                         continue;
269
270                 /* plane is active, safety check if it is supported */
271                 if (!is_plane_supported(drm, plane))
272                         ALOGE("%s: plane %d is not supported",
273                                  __func__, plane->drm_plane->plane_id);
274
275                 /*
276                  * Disable overlay if it is not active
277                  * or if there is error during setplane
278                  */
279                 if (!plane->active)
280                         plane->handle = 0;
281
282                 if (gralloc_drm_bo_setplane(drm, plane))
283                         plane->active = 0;
284         }
285 }
286
287 /*
288  * Interface for HWC, used to reserve a plane for a layer.
289  */
290 int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
291         buffer_handle_t handle,
292         uint32_t id,
293         uint32_t dst_x,
294         uint32_t dst_y,
295         uint32_t dst_w,
296         uint32_t dst_h,
297         uint32_t src_x,
298         uint32_t src_y,
299         uint32_t src_w,
300         uint32_t src_h)
301 {
302         int j;
303         struct gralloc_drm_handle_t *drm_handle =
304                 gralloc_drm_handle(handle);
305         int plane_count = drm->plane_resources->count_planes;
306         struct gralloc_drm_plane_t *plane = drm->planes;
307
308         /* no supported planes for this handle */
309         if (!drm_handle->plane_mask) {
310                 ALOGE("%s: buffer %p cannot be shown on a plane\n",
311                         __func__, drm_handle);
312                 return -EINVAL;
313         }
314
315         for (j = 0; j < plane_count; j++, plane++) {
316
317                 /*
318                  * handle may be suitable to be shown on a plane, in
319                  * addition we need to check that this particular plane
320                  * is supported by the current implementation
321                  */
322                 if (!is_plane_supported(drm, plane))
323                         continue;
324
325                 /* if plane is available and can support this buffer */
326                 if (!plane->active &&
327                         drm_handle->plane_mask &
328                         (1U << plane->drm_plane->plane_id)) {
329
330                         plane->dst_x = dst_x;
331                         plane->dst_y = dst_y;
332                         plane->dst_w = dst_w;
333                         plane->dst_h = dst_h;
334                         plane->src_x = src_x;
335                         plane->src_y = src_y;
336                         plane->src_w = src_w;
337                         plane->src_h = src_h;
338                         plane->handle = handle;
339                         plane->id = id;
340                         plane->active = 1;
341
342                         return 0;
343                 }
344         }
345
346         /* no free planes available */
347         return -EBUSY;
348 }
349
350 /*
351  * Interface for HWC, used to disable all the overlays. Plane id
352  * is also set to 0 as it should be mappable to a particular layer only
353  * if it has been reserved with 'reserve_plane'.
354  */
355 void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
356 {
357         struct gralloc_drm_plane_t *plane = drm->planes;
358         unsigned int i;
359
360         for (i = 0; i < drm->plane_resources->count_planes; i++, plane++) {
361                 plane->active = 0;
362                 plane->id = 0;
363         }
364 }
365
366 /*
367  * Interface for HWC, used to change handle of a reserved plane.
368  */
369 int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
370         uint32_t id, buffer_handle_t handle)
371 {
372         struct gralloc_drm_plane_t *plane = drm->planes;
373         unsigned i;
374
375         for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
376                 if (plane->active && plane->id == id) {
377                         plane->handle = handle;
378                         return 0;
379                 }
380
381         return -EINVAL;
382 }
383
384 /*
385  * Schedule a page flip.
386  */
387 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
388                 struct gralloc_drm_bo_t *bo)
389 {
390         int ret;
391
392         /* there is another flip pending */
393         while (drm->next_front) {
394                 drm->waiting_flip = 1;
395                 drmHandleEvent(drm->fd, &drm->evctx);
396                 drm->waiting_flip = 0;
397                 if (drm->next_front) {
398                         /* record an error and break */
399                         ALOGE("drmHandleEvent returned without flipping");
400                         drm->current_front = drm->next_front;
401                         drm->next_front = NULL;
402                 }
403         }
404
405         if (!bo)
406                 return 0;
407
408         pthread_mutex_lock(&drm->hdmi_mutex);
409         if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo) {
410
411                 int dst_x1 = 0, dst_y1 = 0;
412
413                 if (drm->hdmi.bo->handle->width > bo->handle->width)
414                         dst_x1 = (drm->hdmi.bo->handle->width - bo->handle->width) / 2;
415                 if (drm->hdmi.bo->handle->height > bo->handle->height)
416                         dst_y1 = (drm->hdmi.bo->handle->height - bo->handle->height) / 2;
417
418                 drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
419                         dst_x1, dst_y1,
420                         dst_x1 + bo->handle->width,
421                         dst_y1 + bo->handle->height,
422                         0, 0, bo->handle->width, bo->handle->height);
423
424                 ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, drm->hdmi.bo->fb_id, 0, NULL);
425                 if (ret && errno != EBUSY)
426                         ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
427                                 strerror(errno), drm->hdmi.crtc_id, drm->hdmi.bo->fb_id);
428         }
429         pthread_mutex_unlock(&drm->hdmi_mutex);
430
431         /* set planes to be displayed */
432         gralloc_drm_set_planes(drm);
433
434         ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
435                         DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
436         if (ret) {
437                 ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
438                         strerror(errno), drm->primary.crtc_id, bo->fb_id);
439                 /* try to set mode for next frame */
440                 if (errno != EBUSY)
441                         drm->first_post = 1;
442         }
443         else
444                 drm->next_front = bo;
445
446         return ret;
447 }
448
449 /*
450  * Wait for the next post.
451  */
452 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
453 {
454         unsigned int current, target;
455         drmVBlank vbl;
456         int ret;
457
458         if (drm->mode_quirk_vmwgfx)
459                 return;
460
461         flip = !!flip;
462
463         memset(&vbl, 0, sizeof(vbl));
464         vbl.request.type = DRM_VBLANK_RELATIVE;
465         if (drm->vblank_secondary)
466                 vbl.request.type |= DRM_VBLANK_SECONDARY;
467         vbl.request.sequence = 0;
468
469         /* get the current vblank */
470         ret = drmWaitVBlank(drm->fd, &vbl);
471         if (ret) {
472                 ALOGW("failed to get vblank");
473                 return;
474         }
475
476         current = vbl.reply.sequence;
477         if (drm->first_post)
478                 target = current;
479         else
480                 target = drm->last_swap + drm->swap_interval - flip;
481
482         /* wait for vblank */
483         if (current < target || !flip) {
484                 memset(&vbl, 0, sizeof(vbl));
485                 vbl.request.type = DRM_VBLANK_ABSOLUTE;
486                 if (drm->vblank_secondary)
487                         vbl.request.type |= DRM_VBLANK_SECONDARY;
488                 if (!flip) {
489                         vbl.request.type |= DRM_VBLANK_NEXTONMISS;
490                         if (target < current)
491                                 target = current;
492                 }
493
494                 vbl.request.sequence = target;
495
496                 ret = drmWaitVBlank(drm->fd, &vbl);
497                 if (ret) {
498                         ALOGW("failed to wait vblank");
499                         return;
500                 }
501         }
502
503         drm->last_swap = vbl.reply.sequence + flip;
504 }
505
506 /*
507  * Post a bo.  This is not thread-safe.
508  */
509 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
510 {
511         struct gralloc_drm_t *drm = bo->drm;
512         int ret;
513
514         if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
515                 ALOGE("unable to post bo %p without fb", bo);
516                 return -EINVAL;
517         }
518
519         /* TODO spawn a thread to avoid waiting and race */
520
521         if (drm->first_post) {
522                 if (drm->swap_mode == DRM_SWAP_COPY) {
523                         struct gralloc_drm_bo_t *dst;
524
525                         dst = (drm->next_front) ?
526                                 drm->next_front :
527                                 drm->current_front;
528                         drm->drv->blit(drm->drv, dst, bo, 0, 0,
529                                         bo->handle->width,
530                                         bo->handle->height,
531                                         0, 0,
532                                         bo->handle->width,
533                                         bo->handle->height);
534                         bo = dst;
535                 }
536
537                 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
538                 if (!ret) {
539                         drm->first_post = 0;
540                         drm->current_front = bo;
541                         if (drm->next_front == bo)
542                                 drm->next_front = NULL;
543                 }
544
545                 pthread_mutex_lock(&drm->hdmi_mutex);
546                 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
547                         drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
548                 pthread_mutex_unlock(&drm->hdmi_mutex);
549
550                 return ret;
551         }
552
553         switch (drm->swap_mode) {
554         case DRM_SWAP_FLIP:
555                 if (drm->swap_interval > 1)
556                         drm_kms_wait_for_post(drm, 1);
557                 ret = drm_kms_page_flip(drm, bo);
558                 if (drm->next_front) {
559                         /*
560                          * wait if the driver says so or the current front
561                          * will be written by CPU
562                          */
563                         if (drm->mode_sync_flip ||
564                             (drm->current_front->handle->usage &
565                              GRALLOC_USAGE_SW_WRITE_MASK))
566                                 drm_kms_page_flip(drm, NULL);
567                 }
568                 break;
569         case DRM_SWAP_COPY:
570                 drm_kms_wait_for_post(drm, 0);
571                 drm->drv->blit(drm->drv, drm->current_front,
572                                 bo, 0, 0,
573                                 bo->handle->width,
574                                 bo->handle->height,
575                                 0, 0,
576                                 bo->handle->width,
577                                 bo->handle->height);
578                 if (drm->mode_quirk_vmwgfx)
579                         ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
580                 ret = 0;
581                 break;
582         case DRM_SWAP_SETCRTC:
583                 drm_kms_wait_for_post(drm, 0);
584                 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
585
586                 pthread_mutex_lock(&drm->hdmi_mutex);
587                 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
588                         drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
589                 pthread_mutex_unlock(&drm->hdmi_mutex);
590
591                 drm->current_front = bo;
592                 break;
593         default:
594                 /* no-op */
595                 ret = 0;
596                 break;
597         }
598
599         return ret;
600 }
601
602 static struct gralloc_drm_t *drm_singleton;
603
604 static void on_signal(int sig)
605 {
606         struct gralloc_drm_t *drm = drm_singleton;
607
608         /* wait the pending flip */
609         if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
610                 /* there is race, but this function is hacky enough to ignore that */
611                 if (drm_singleton->waiting_flip)
612                         usleep(100 * 1000); /* 100ms */
613                 else
614                         drm_kms_page_flip(drm_singleton, NULL);
615         }
616
617         exit(-1);
618 }
619
620 static void drm_kms_init_features(struct gralloc_drm_t *drm)
621 {
622         const char *swap_mode;
623
624         /* call to the driver here, after KMS has been initialized */
625         drm->drv->init_kms_features(drm->drv, drm);
626
627         if (drm->swap_mode == DRM_SWAP_FLIP) {
628                 struct sigaction act;
629
630                 memset(&drm->evctx, 0, sizeof(drm->evctx));
631                 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
632                 drm->evctx.page_flip_handler = page_flip_handler;
633
634                 /*
635                  * XXX GPU tends to freeze if the program is terminiated with a
636                  * flip pending.  What is the right way to handle the
637                  * situation?
638                  */
639                 sigemptyset(&act.sa_mask);
640                 act.sa_handler = on_signal;
641                 act.sa_flags = 0;
642                 sigaction(SIGINT, &act, NULL);
643                 sigaction(SIGTERM, &act, NULL);
644
645                 drm_singleton = drm;
646         }
647         else if (drm->swap_mode == DRM_SWAP_COPY) {
648                 struct gralloc_drm_bo_t *front;
649                 int stride;
650
651                 /* create the real front buffer */
652                 front = gralloc_drm_bo_create(drm,
653                                               drm->primary.mode.hdisplay,
654                                               drm->primary.mode.vdisplay,
655                                               drm->primary.fb_format,
656                                               GRALLOC_USAGE_HW_FB);
657                 if (front && gralloc_drm_bo_add_fb(front)) {
658                         gralloc_drm_bo_decref(front);
659                         front = NULL;
660                 }
661
662                 /* abuse next_front */
663                 if (front)
664                         drm->next_front = front;
665                 else
666                         drm->swap_mode = DRM_SWAP_SETCRTC;
667         }
668
669         switch (drm->swap_mode) {
670         case DRM_SWAP_FLIP:
671                 swap_mode = "flip";
672                 break;
673         case DRM_SWAP_COPY:
674                 swap_mode = "copy";
675                 break;
676         case DRM_SWAP_SETCRTC:
677                 swap_mode = "set-crtc";
678                 break;
679         default:
680                 swap_mode = "no-op";
681                 break;
682         }
683
684         ALOGD("will use %s for fb posting", swap_mode);
685 }
686
687 #define MARGIN_PERCENT 1.8   /* % of active vertical image*/
688 #define CELL_GRAN 8.0   /* assumed character cell granularity*/
689 #define MIN_PORCH 1 /* minimum front porch   */
690 #define V_SYNC_RQD 3 /* width of vsync in lines   */
691 #define H_SYNC_PERCENT 8.0   /* width of hsync as % of total line */
692 #define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
693 #define M 600.0 /* blanking formula gradient */
694 #define C 40.0  /* blanking formula offset   */
695 #define K 128.0 /* blanking formula scaling factor   */
696 #define J 20.0  /* blanking formula scaling factor   */
697 /* C' and M' are part of the Blanking Duty Cycle computation */
698 #define C_PRIME   (((C - J) * K / 256.0) + J)
699 #define M_PRIME   (K / 256.0 * M)
700
701 static drmModeModeInfoPtr generate_mode(int h_pixels, int v_lines, float freq)
702 {
703         float h_pixels_rnd;
704         float v_lines_rnd;
705         float v_field_rate_rqd;
706         float top_margin;
707         float bottom_margin;
708         float interlace;
709         float h_period_est;
710         float vsync_plus_bp;
711         float v_back_porch;
712         float total_v_lines;
713         float v_field_rate_est;
714         float h_period;
715         float v_field_rate;
716         float v_frame_rate;
717         float left_margin;
718         float right_margin;
719         float total_active_pixels;
720         float ideal_duty_cycle;
721         float h_blank;
722         float total_pixels;
723         float pixel_freq;
724         float h_freq;
725
726         float h_sync;
727         float h_front_porch;
728         float v_odd_front_porch_lines;
729         int interlaced = 0;
730         int margins = 0;
731
732         drmModeModeInfoPtr m = malloc(sizeof(drmModeModeInfo));
733
734         h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
735         v_lines_rnd = interlaced ? rint((float) v_lines) / 2.0 : rint((float) v_lines);
736         v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
737         top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
738         bottom_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
739         interlace = interlaced ? 0.5 : 0.0;
740         h_period_est = (((1.0 / v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP / 1000000.0)) / (v_lines_rnd + (2 * top_margin) + MIN_PORCH + interlace) * 1000000.0);
741         vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est);
742         v_back_porch = vsync_plus_bp - V_SYNC_RQD;
743         total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + interlace + MIN_PORCH;
744         v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
745         h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
746         v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
747         v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
748         left_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
749         right_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
750         total_active_pixels = h_pixels_rnd + left_margin + right_margin;
751         ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
752         h_blank = rint(total_active_pixels * ideal_duty_cycle / (100.0 - ideal_duty_cycle) / (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
753         total_pixels = total_active_pixels + h_blank;
754         pixel_freq = total_pixels / h_period;
755         h_freq = 1000.0 / h_period;
756         h_sync = rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
757         h_front_porch = (h_blank / 2.0) - h_sync;
758         v_odd_front_porch_lines = MIN_PORCH + interlace;
759
760         m->clock = ceil(pixel_freq) * 1000;
761         m->hdisplay = (int) (h_pixels_rnd);
762         m->hsync_start = (int) (h_pixels_rnd + h_front_porch);
763         m->hsync_end = (int) (h_pixels_rnd + h_front_porch + h_sync);
764         m->htotal = (int) (total_pixels);
765         m->hskew = 0;
766         m->vdisplay = (int) (v_lines_rnd);
767         m->vsync_start = (int) (v_lines_rnd + v_odd_front_porch_lines);
768         m->vsync_end = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
769         m->vtotal = (int) (total_v_lines);
770         m->vscan = 0;
771         m->vrefresh = freq;
772         m->flags = 10;
773         m->type = 64;
774
775         return (m);
776 }
777
778 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
779 {
780         char value[PROPERTY_VALUE_MAX];
781         drmModeModeInfoPtr mode;
782         int dist, i;
783         int xres = 0, yres = 0, rate = 0;
784         int forcemode = 0;
785
786         if (property_get("debug.drm.mode", value, NULL)) {
787                 char *p = value, *end;
788
789                 /* parse <xres>x<yres>[@<bpp>] */
790                 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
791                         *bpp = 0;
792                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
793                                 xres = yres = 0;
794                 }
795
796                 if ((xres && yres) || *bpp) {
797                         ALOGI("will find the closest match for %dx%d@%d",
798                                         xres, yres, *bpp);
799                 }
800         } else if (property_get("debug.drm.mode.force", value, NULL)) {
801                 char *p = value, *end;
802                 *bpp = 0;
803
804                 /* parse <xres>x<yres>[@<refreshrate>] */
805                 if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
806                         rate = 60;
807                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
808                                 xres = yres = 0;
809                 }
810
811                 if (xres && yres && rate) {
812                         ALOGI("will use %dx%d@%dHz", xres, yres, rate);
813                         forcemode = 1;
814                 }
815         } else {
816                 *bpp = 0;
817         }
818
819         dist = INT_MAX;
820
821         if (forcemode)
822                 mode = generate_mode(xres, yres, rate);
823         else {
824                 mode = NULL;
825                 for (i = 0; i < connector->count_modes; i++) {
826                         drmModeModeInfoPtr m = &connector->modes[i];
827                         int tmp;
828
829                         if (xres && yres) {
830                                 tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
831                                         (m->vdisplay - yres) * (m->vdisplay - yres);
832                         }
833                         else {
834                                 /* use the first preferred mode */
835                                 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
836                         }
837
838                         if (tmp < dist) {
839                                 mode = m;
840                                 dist = tmp;
841                                 if (!dist)
842                                         break;
843                         }
844                 }
845         }
846
847         /* fallback to the first mode */
848         if (!mode)
849                 mode = &connector->modes[0];
850
851         ALOGI("Established mode:");
852         ALOGI("clock: %d, hdisplay: %d, hsync_start: %d, hsync_end: %d, htotal: %d, hskew: %d", mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->hskew);
853         ALOGI("vdisplay: %d, vsync_start: %d, vsync_end: %d, vtotal: %d, vscan: %d, vrefresh: %d", mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, mode->vscan, mode->vrefresh);
854         ALOGI("flags: %d, type: %d, name %s", mode->flags, mode->type, mode->name);
855
856         *bpp /= 8;
857
858         return mode;
859 }
860
861 /*
862  * Initialize KMS with a connector.
863  */
864 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
865                 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
866 {
867         drmModeEncoderPtr encoder;
868         drmModeModeInfoPtr mode;
869         static int used_crtcs = 0;
870         int bpp, i;
871
872         if (!connector->count_modes)
873                 return -EINVAL;
874
875         encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
876         if (!encoder)
877                 return -EINVAL;
878
879         /* find first possible crtc which is not used yet */
880         for (i = 0; i < drm->resources->count_crtcs; i++) {
881                 if (encoder->possible_crtcs & (1 << i) &&
882                         (used_crtcs & (1 << i)) != (1 << i))
883                         break;
884         }
885
886         used_crtcs |= (1 << i);
887
888         drmModeFreeEncoder(encoder);
889         if (i == drm->resources->count_crtcs)
890                 return -EINVAL;
891
892         output->bo = NULL;
893         output->crtc_id = drm->resources->crtcs[i];
894         output->connector_id = connector->connector_id;
895         output->pipe = i;
896
897         /* print connector info */
898         if (connector->count_modes > 1) {
899                 ALOGI("there are %d modes on connector 0x%x, type %d",
900                                 connector->count_modes,
901                                 connector->connector_id,
902                                 connector->connector_type);
903                 for (i = 0; i < connector->count_modes; i++)
904                         ALOGI("  %s", connector->modes[i].name);
905         }
906         else {
907                 ALOGI("there is one mode on connector 0x%d: %s",
908                                 connector->connector_id,
909                                 connector->modes[0].name);
910         }
911
912         mode = find_mode(connector, &bpp);
913
914         ALOGI("the best mode is %s", mode->name);
915
916         output->mode = *mode;
917         switch (bpp) {
918         case 2:
919                 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
920                 break;
921         case 4:
922         default:
923                 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
924                 break;
925         }
926
927         if (connector->mmWidth && connector->mmHeight) {
928                 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
929                 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
930         }
931         else {
932                 output->xdpi = 75;
933                 output->ydpi = 75;
934         }
935
936 #ifdef DRM_MODE_FEATURE_DIRTYFB
937         drm->clip.x1 = 0;
938         drm->clip.y1 = 0;
939         drm->clip.x2 = output->mode.hdisplay;
940         drm->clip.y2 = output->mode.vdisplay;
941 #endif
942
943         return 0;
944 }
945
946
947 /*
948  * Fetch a connector of particular type
949  */
950 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
951         uint32_t type)
952 {
953         int i;
954
955         if (!drm->resources)
956                 return NULL;
957
958         for (i = 0; i < drm->resources->count_connectors; i++) {
959                 drmModeConnectorPtr connector =
960                         connector = drmModeGetConnector(drm->fd,
961                                 drm->resources->connectors[i]);
962                 if (connector) {
963                         if (connector->connector_type == type &&
964                                 connector->connection == DRM_MODE_CONNECTED)
965                                 return connector;
966                         drmModeFreeConnector(connector);
967                 }
968         }
969         return NULL;
970 }
971
972
973 /*
974  * Initializes hdmi output with a connector and allocates
975  * a private framebuffer for it. This is called on startup if
976  * hdmi cable is connected and also on hotplug events.
977  */
978 static void init_hdmi_output(struct gralloc_drm_t *drm,
979         drmModeConnectorPtr connector)
980 {
981         drm_kms_init_with_connector(drm, &drm->hdmi, connector);
982
983         ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
984                 __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
985
986         drm->hdmi.bo = gralloc_drm_bo_create(drm,
987                 drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
988                 drm->hdmi.fb_format,
989                 GRALLOC_USAGE_HW_RENDER);
990
991         int err = gralloc_drm_bo_add_fb(drm->hdmi.bo);
992         if (err) {
993                 ALOGE("%s: could not create drm fb, (%s)",
994                         __func__, strerror(-err));
995                 return err;
996         }
997
998         drm->hdmi_mode = HDMI_CLONED;
999         drm->hdmi.active = 1;
1000 }
1001
1002
1003 /*
1004  * Thread that listens to uevents and checks if hdmi state changes
1005  */
1006 static void *hdmi_observer(void *data)
1007 {
1008         static char uevent_desc[4096];
1009         drmModeConnectorPtr hdmi;
1010         struct gralloc_drm_t *drm =
1011                 (struct gralloc_drm_t *) data;
1012
1013         uevent_init();
1014
1015         memset(uevent_desc, 0, sizeof(uevent_desc));
1016
1017         while(1) {
1018
1019                 /* this polls */
1020                 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
1021
1022                 if(len && strstr(uevent_desc, "devices/virtual/switch/hdmi")) {
1023
1024                         /* check what changed */
1025                         const char *prop = uevent_desc + strlen(uevent_desc) + 1;
1026
1027                         while (*prop) {
1028
1029                                 const char *state = strstr(prop, "SWITCH_STATE=");
1030                                 if (state) {
1031                                         unsigned int value = 0;
1032                                         state += strlen("SWITCH_STATE=");
1033                                         value = atoi(state);
1034
1035                                         pthread_mutex_lock(&drm->hdmi_mutex);
1036
1037                                         if (value) {
1038                                                 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1039                                                 if (hdmi) {
1040
1041                                                         ALOGD("init hdmi on hotplug event");
1042                                                         init_hdmi_output(drm, hdmi);
1043
1044                                                         /* will trigger modeset */
1045                                                         drm->first_post = 1;
1046
1047                                                         drmModeFreeConnector(hdmi);
1048
1049                                                         pthread_mutex_unlock(&drm->hdmi_mutex);
1050                                                 }
1051                                                 break;
1052                                         } else {
1053                                                 drm->hdmi.active = 0;
1054
1055                                                 ALOGD("destroy hdmi private buffer");
1056                                                 gralloc_drm_bo_decref(drm->hdmi.bo);
1057                                                 drm->hdmi.bo = NULL;
1058
1059                                                 pthread_mutex_unlock(&drm->hdmi_mutex);
1060                                                 break;
1061                                         }
1062
1063                                         pthread_mutex_unlock(&drm->hdmi_mutex);
1064                                 }
1065
1066                                 /* next property/value pair */
1067                                 prop += strlen(prop) + 1;
1068                                 if (prop - uevent_desc >= len)
1069                                         break;
1070                         }
1071                 }
1072         }
1073
1074         pthread_exit(NULL);
1075         return 0;
1076 }
1077
1078
1079 /*
1080  * Initialize KMS.
1081  */
1082 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
1083 {
1084         drmModeConnectorPtr lvds, hdmi;
1085         int i, ret;
1086
1087         if (drm->resources)
1088                 return 0;
1089
1090         drm->resources = drmModeGetResources(drm->fd);
1091         if (!drm->resources) {
1092                 ALOGE("failed to get modeset resources");
1093                 return -EINVAL;
1094         }
1095
1096         drm->plane_resources = drmModeGetPlaneResources(drm->fd);
1097         if (!drm->plane_resources) {
1098                 ALOGD("no planes found from drm resources");
1099         } else {
1100                 unsigned int i, j;
1101
1102                 ALOGD("supported drm planes and formats");
1103                 /* fill a helper structure for hwcomposer */
1104                 drm->planes = calloc(drm->plane_resources->count_planes,
1105                         sizeof(struct gralloc_drm_plane_t));
1106
1107                 for (i = 0; i < drm->plane_resources->count_planes; i++) {
1108                         drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
1109                                 drm->plane_resources->planes[i]);
1110
1111                         ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
1112                         for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
1113                                 ALOGD("    format %c%c%c%c",
1114                                         (drm->planes[i].drm_plane->formats[j]),
1115                                         (drm->planes[i].drm_plane->formats[j])>>8,
1116                                         (drm->planes[i].drm_plane->formats[j])>>16,
1117                                         (drm->planes[i].drm_plane->formats[j])>>24);
1118                 }
1119         }
1120
1121         /* find the crtc/connector/mode to use */
1122         lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
1123         if (lvds) {
1124                 drm_kms_init_with_connector(drm, &drm->primary, lvds);
1125                 drmModeFreeConnector(lvds);
1126                 drm->primary.active = 1;
1127         }
1128
1129         /* if still no connector, find first connected connector and try it */
1130         if (!drm->primary.active) {
1131
1132                 for (i = 0; i < drm->resources->count_connectors; i++) {
1133                         drmModeConnectorPtr connector;
1134
1135                         connector = drmModeGetConnector(drm->fd,
1136                                         drm->resources->connectors[i]);
1137                         if (connector) {
1138                                 if (connector->connection == DRM_MODE_CONNECTED) {
1139                                         if (!drm_kms_init_with_connector(drm,
1140                                                         &drm->primary, connector))
1141                                                 break;
1142                                 }
1143
1144                                 drmModeFreeConnector(connector);
1145                         }
1146                 }
1147                 if (i == drm->resources->count_connectors) {
1148                         ALOGE("failed to find a valid crtc/connector/mode combination");
1149                         drmModeFreeResources(drm->resources);
1150                         drm->resources = NULL;
1151
1152                         return -EINVAL;
1153                 }
1154         }
1155
1156
1157         /* check if hdmi is connected already */
1158         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1159         if (hdmi) {
1160
1161                 if (hdmi->connector_id == drm->primary.connector_id) {
1162                         /* special case: our primary connector is hdmi */
1163                         ALOGD("hdmi is the primary connector");
1164                         goto skip_hdmi_modes;
1165                 }
1166
1167                 ALOGD("init hdmi on startup");
1168                 init_hdmi_output(drm, hdmi);
1169
1170                 drmModeFreeConnector(hdmi);
1171         }
1172
1173 goto skip_hdmi_modes;
1174         /* launch hdmi observer thread */
1175         pthread_mutex_init(&drm->hdmi_mutex, NULL);
1176         pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
1177
1178 skip_hdmi_modes:
1179
1180         drm_kms_init_features(drm);
1181         drm->first_post = 1;
1182
1183         return 0;
1184 }
1185
1186 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1187 {
1188         switch (drm->swap_mode) {
1189         case DRM_SWAP_FLIP:
1190                 drm_kms_page_flip(drm, NULL);
1191                 break;
1192         case DRM_SWAP_COPY:
1193                 {
1194                         struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1195                                 &drm->current_front : &drm->next_front;
1196
1197                         if (*bo)
1198                                 gralloc_drm_bo_decref(*bo);
1199                         *bo = NULL;
1200                 }
1201                 break;
1202         default:
1203                 break;
1204         }
1205
1206         /* restore crtc? */
1207
1208         if (drm->resources) {
1209                 drmModeFreeResources(drm->resources);
1210                 drm->resources = NULL;
1211         }
1212
1213         if (drm->planes) {
1214                 unsigned int i;
1215                 for (i = 0; i < drm->plane_resources->count_planes; i++)
1216                         drmModeFreePlane(drm->planes[i].drm_plane);
1217                 free(drm->planes);
1218                 drm->planes = NULL;
1219         }
1220
1221         if (drm->plane_resources) {
1222                 drmModeFreePlaneResources(drm->plane_resources);
1223                 drm->plane_resources = NULL;
1224         }
1225
1226         /* destroy private buffer of hdmi output */
1227         if (drm->hdmi.bo)
1228                 gralloc_drm_bo_decref(drm->hdmi.bo);
1229
1230         drm_singleton = NULL;
1231 }
1232
1233 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1234 {
1235         return (drm->resources != NULL);
1236 }
1237
1238 /*
1239  * Initialize a framebuffer device with KMS info.
1240  */
1241 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1242                 struct framebuffer_device_t *fb)
1243 {
1244         *((uint32_t *) &fb->flags) = 0x0;
1245         *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
1246         *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
1247         *((int *)      &fb->stride) = drm->primary.mode.hdisplay;
1248         *((float *)    &fb->fps) = drm->primary.mode.vrefresh;
1249
1250         *((int *)      &fb->format) = drm->primary.fb_format;
1251         *((float *)    &fb->xdpi) = drm->primary.xdpi;
1252         *((float *)    &fb->ydpi) = drm->primary.ydpi;
1253         *((int *)      &fb->minSwapInterval) = drm->swap_interval;
1254         *((int *)      &fb->maxSwapInterval) = drm->swap_interval;
1255 }
1256
1257 /*
1258  * Return true if fb posting is pipelined.
1259  */
1260 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1261 {
1262         return (drm->swap_mode != DRM_SWAP_SETCRTC);
1263 }