OSDN Git Service

gralloc: plane support
[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 "gralloc_drm.h"
35 #include "gralloc_drm_priv.h"
36 #include <hardware_legacy/uevent.h>
37
38 #include <drm_fourcc.h>
39
40 /*
41  * Return true if a bo needs fb.
42  */
43 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
44 {
45         return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
46                 bo->drm->swap_mode != DRM_SWAP_COPY);
47 }
48
49 static unsigned int drm_format_from_hal(int hal_format)
50 {
51         switch(hal_format) {
52                 case HAL_PIXEL_FORMAT_RGB_888:
53                 case HAL_PIXEL_FORMAT_RGBX_8888:
54                 case HAL_PIXEL_FORMAT_BGRA_8888:
55                         return DRM_FORMAT_XRGB8888;
56                 case HAL_PIXEL_FORMAT_RGBA_8888:
57                         return DRM_FORMAT_RGBA8888;
58                 case HAL_PIXEL_FORMAT_RGB_565:
59                         return DRM_FORMAT_RGB565;
60                 case HAL_PIXEL_FORMAT_YV12:
61                         return DRM_FORMAT_YUV420;
62                 case HAL_PIXEL_FORMAT_DRM_NV12:
63                         return DRM_FORMAT_NV12;
64                 default:
65                         return 0;
66         }
67 }
68
69 /*
70  * Modify pitches, offsets and handles according to
71  * the format and return corresponding drm format value
72  */
73 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
74         uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
75 {
76         struct gralloc_drm_t *drm = bo->drm;
77
78         pitches[0] = bo->handle->stride;
79         handles[0] = bo->fb_handle;
80
81         /* driver takes care of HW specific padding, alignment etc. */
82         if (drm->drv->resolve_format)
83                 drm->drv->resolve_format(drm->drv, bo,
84                         pitches, offsets, handles);
85
86         return drm_format_from_hal(bo->handle->format);
87 }
88
89 /*
90  * Returns planes that are supported for a particular format
91  */
92 unsigned int planes_for_format(struct gralloc_drm_t *drm,
93         int hal_format)
94 {
95         unsigned int i, j, mask = 0;
96         unsigned int drm_format = drm_format_from_hal(hal_format);
97         struct gralloc_drm_plane_t *plane = drm->planes;
98
99         /* no planes available */
100         if (!plane)
101                 return 0;
102
103         /* iterate through planes, mark those that match format */
104         for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
105                 for (j=0; j<plane->drm_plane->count_formats; j++)
106                         if (plane->drm_plane->formats[j] == drm_format)
107                                 mask |= (1U << plane->drm_plane->plane_id);
108
109         return mask;
110 }
111
112 /*
113  * Add a fb object for a bo.
114  */
115 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
116 {
117         uint32_t pitches[4] = { 0, 0, 0, 0 };
118         uint32_t offsets[4] = { 0, 0, 0, 0 };
119         uint32_t handles[4] = { 0, 0, 0, 0 };
120
121         if (bo->fb_id)
122                 return 0;
123
124         int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
125
126         if (drm_format == 0) {
127                 ALOGE("error resolving drm format");
128                 return -EINVAL;
129         }
130
131         return drmModeAddFB2(bo->drm->fd,
132                 bo->handle->width, bo->handle->height,
133                 drm_format, handles, pitches, offsets,
134                 (uint32_t *) &bo->fb_id, 0);
135 }
136
137 /*
138  * Remove a fb object for a bo.
139  */
140 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
141 {
142         if (bo->fb_id) {
143                 drmModeRmFB(bo->drm->fd, bo->fb_id);
144                 bo->fb_id = 0;
145         }
146 }
147
148 /*
149  * Program CRTC.
150  */
151 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
152         struct gralloc_drm_output *output, int fb_id)
153 {
154         int ret;
155
156         ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
157                         0, 0, &output->connector_id, 1, &output->mode);
158         if (ret) {
159                 ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
160                         strerror(errno), output->crtc_id, fb_id, output->connector_id,
161                         output->mode.hdisplay, output->mode.vdisplay);
162                 return ret;
163         }
164
165         if (drm->mode_quirk_vmwgfx)
166                 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
167
168         return ret;
169 }
170
171 /*
172  * Callback for a page flip event.
173  */
174 static void page_flip_handler(int fd, unsigned int sequence,
175                 unsigned int tv_sec, unsigned int tv_usec,
176                 void *user_data)
177 {
178         struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
179
180         /* ack the last scheduled flip */
181         drm->current_front = drm->next_front;
182         drm->next_front = NULL;
183 }
184
185 /*
186  * Set a plane.
187  */
188 static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
189         struct gralloc_drm_plane_t *plane)
190 {
191         struct gralloc_drm_bo_t *bo = NULL;
192         int err;
193
194         if (plane->handle)
195                 bo = gralloc_drm_bo_from_handle(plane->handle);
196
197         // create a framebuffer if does not exist
198         if (bo && bo->fb_id == 0) {
199                 err = gralloc_drm_bo_add_fb(bo);
200                 if (err) {
201                         ALOGE("%s: could not create drm fb, (%s)",
202                                 __func__, strerror(-err));
203                         return err;
204                 }
205         }
206
207         err = drmModeSetPlane(drm->fd,
208                 plane->drm_plane->plane_id,
209                 drm->primary.crtc_id,
210                 bo ? bo->fb_id : 0,
211                 0, // flags
212                 plane->dst_x,
213                 plane->dst_y,
214                 plane->dst_w,
215                 plane->dst_h,
216                 plane->src_x << 16,
217                 plane->src_y << 16,
218                 plane->src_w << 16,
219                 plane->src_h << 16);
220
221         if (err) {
222                 /* clear plane_mask so that this buffer won't be tried again */
223                 struct gralloc_drm_handle_t *drm_handle =
224                         (struct gralloc_drm_handle_t *) plane->handle;
225                 drm_handle->plane_mask = 0;
226
227                 ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
228                         strerror(-err),
229                         plane->drm_plane->plane_id,
230                         drm->primary.crtc_id,
231                         bo ? bo->fb_id : 0);
232         }
233
234         if (plane->prev)
235                 gralloc_drm_bo_decref(plane->prev);
236
237         if (bo)
238                 bo->refcount++;
239
240         plane->prev = bo;
241
242         return err;
243 }
244
245 /*
246  * Sets all the active planes to be displayed.
247  */
248 static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
249 {
250         struct gralloc_drm_plane_t *plane = drm->planes;
251         unsigned int i;
252         for (i = 0; i < drm->plane_resources->count_planes;
253                 i++, plane++) {
254                 /*
255                  * Disable overlay if it is not active
256                  * or if there is error during setplane
257                  */
258                 if (!plane->active)
259                         plane->handle = 0;
260
261                 if (gralloc_drm_bo_setplane(drm, plane))
262                         plane->active = 0;
263         }
264 }
265
266 /*
267  * Interface for HWC, used to reserve a plane for a layer.
268  */
269 int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
270         buffer_handle_t handle,
271         uint32_t dst_x,
272         uint32_t dst_y,
273         uint32_t dst_w,
274         uint32_t dst_h,
275         uint32_t src_x,
276         uint32_t src_y,
277         uint32_t src_w,
278         uint32_t src_h)
279 {
280         unsigned int i, j;
281         struct gralloc_drm_handle_t *drm_handle =
282                 gralloc_drm_handle(handle);
283         int plane_count = drm->plane_resources->count_planes;
284         struct gralloc_drm_plane_t *plane = drm->planes;
285
286         /* no supported planes for this handle */
287         if (!drm_handle->plane_mask) {
288                 ALOGE("%s: buffer %p cannot be shown on a plane\n",
289                         __func__, drm_handle);
290                 return -EINVAL;
291         }
292
293         for (j = 0; j < plane_count; j++, plane++) {
294                 /* if plane is available and can support this buffer */
295                 if (!plane->active &&
296                         drm_handle->plane_mask &
297                         (1U << plane->drm_plane->plane_id)) {
298
299                         plane->dst_x = dst_x;
300                         plane->dst_y = dst_y;
301                         plane->dst_w = dst_w;
302                         plane->dst_h = dst_h;
303                         plane->src_x = src_x;
304                         plane->src_y = src_y;
305                         plane->src_w = src_w;
306                         plane->src_h = src_h;
307                         plane->handle = handle;
308                         plane->active = 1;
309
310                         return 0;
311                 }
312         }
313
314         /* no free planes available */
315         return -EBUSY;
316 }
317
318 /*
319  * Interface for HWC, used to disable all the overlays.
320  */
321 void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
322 {
323         struct gralloc_drm_plane_t *plane = drm->planes;
324         unsigned int i;
325
326         for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
327                 plane->active = 0;
328 }
329
330
331 /*
332  * Schedule a page flip.
333  */
334 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
335                 struct gralloc_drm_bo_t *bo)
336 {
337         int ret;
338
339         /* there is another flip pending */
340         while (drm->next_front) {
341                 drm->waiting_flip = 1;
342                 drmHandleEvent(drm->fd, &drm->evctx);
343                 drm->waiting_flip = 0;
344                 if (drm->next_front) {
345                         /* record an error and break */
346                         ALOGE("drmHandleEvent returned without flipping");
347                         drm->current_front = drm->next_front;
348                         drm->next_front = NULL;
349                 }
350         }
351
352         if (!bo)
353                 return 0;
354
355         pthread_mutex_lock(&drm->hdmi_mutex);
356         if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo) {
357
358                 int dst_x1 = 0, dst_y1 = 0;
359
360                 if (drm->hdmi.bo->handle->width > bo->handle->width)
361                         dst_x1 = (drm->hdmi.bo->handle->width - bo->handle->width) / 2;
362                 if (drm->hdmi.bo->handle->height > bo->handle->height)
363                         dst_y1 = (drm->hdmi.bo->handle->height - bo->handle->height) / 2;
364
365                 drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
366                         dst_x1, dst_y1,
367                         dst_x1 + bo->handle->width,
368                         dst_y1 + bo->handle->height,
369                         0, 0, bo->handle->width, bo->handle->height);
370
371                 ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, drm->hdmi.bo->fb_id, 0, NULL);
372                 if (ret && errno != EBUSY)
373                         ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
374                                 strerror(errno), drm->hdmi.crtc_id, drm->hdmi.bo->fb_id);
375         }
376         pthread_mutex_unlock(&drm->hdmi_mutex);
377
378         /* set planes to be displayed */
379         gralloc_drm_set_planes(drm);
380
381         ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
382                         DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
383         if (ret) {
384                 ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
385                         strerror(errno), drm->primary.crtc_id, bo->fb_id);
386                 /* try to set mode for next frame */
387                 if (errno != EBUSY)
388                         drm->first_post = 1;
389         }
390         else
391                 drm->next_front = bo;
392
393         return ret;
394 }
395
396 /*
397  * Wait for the next post.
398  */
399 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
400 {
401         unsigned int current, target;
402         drmVBlank vbl;
403         int ret;
404
405         if (drm->mode_quirk_vmwgfx)
406                 return;
407
408         flip = !!flip;
409
410         memset(&vbl, 0, sizeof(vbl));
411         vbl.request.type = DRM_VBLANK_RELATIVE;
412         if (drm->vblank_secondary)
413                 vbl.request.type |= DRM_VBLANK_SECONDARY;
414         vbl.request.sequence = 0;
415
416         /* get the current vblank */
417         ret = drmWaitVBlank(drm->fd, &vbl);
418         if (ret) {
419                 ALOGW("failed to get vblank");
420                 return;
421         }
422
423         current = vbl.reply.sequence;
424         if (drm->first_post)
425                 target = current;
426         else
427                 target = drm->last_swap + drm->swap_interval - flip;
428
429         /* wait for vblank */
430         if (current < target || !flip) {
431                 memset(&vbl, 0, sizeof(vbl));
432                 vbl.request.type = DRM_VBLANK_ABSOLUTE;
433                 if (drm->vblank_secondary)
434                         vbl.request.type |= DRM_VBLANK_SECONDARY;
435                 if (!flip) {
436                         vbl.request.type |= DRM_VBLANK_NEXTONMISS;
437                         if (target < current)
438                                 target = current;
439                 }
440
441                 vbl.request.sequence = target;
442
443                 ret = drmWaitVBlank(drm->fd, &vbl);
444                 if (ret) {
445                         ALOGW("failed to wait vblank");
446                         return;
447                 }
448         }
449
450         drm->last_swap = vbl.reply.sequence + flip;
451 }
452
453 /*
454  * Post a bo.  This is not thread-safe.
455  */
456 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
457 {
458         struct gralloc_drm_t *drm = bo->drm;
459         int ret;
460
461         if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
462                 ALOGE("unable to post bo %p without fb", bo);
463                 return -EINVAL;
464         }
465
466         /* TODO spawn a thread to avoid waiting and race */
467
468         if (drm->first_post) {
469                 if (drm->swap_mode == DRM_SWAP_COPY) {
470                         struct gralloc_drm_bo_t *dst;
471
472                         dst = (drm->next_front) ?
473                                 drm->next_front :
474                                 drm->current_front;
475                         drm->drv->blit(drm->drv, dst, bo, 0, 0,
476                                         bo->handle->width,
477                                         bo->handle->height,
478                                         0, 0,
479                                         bo->handle->width,
480                                         bo->handle->height);
481                         bo = dst;
482                 }
483
484                 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
485                 if (!ret) {
486                         drm->first_post = 0;
487                         drm->current_front = bo;
488                         if (drm->next_front == bo)
489                                 drm->next_front = NULL;
490                 }
491
492                 pthread_mutex_lock(&drm->hdmi_mutex);
493                 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
494                         drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
495                 pthread_mutex_unlock(&drm->hdmi_mutex);
496
497                 return ret;
498         }
499
500         switch (drm->swap_mode) {
501         case DRM_SWAP_FLIP:
502                 if (drm->swap_interval > 1)
503                         drm_kms_wait_for_post(drm, 1);
504                 ret = drm_kms_page_flip(drm, bo);
505                 if (drm->next_front) {
506                         /*
507                          * wait if the driver says so or the current front
508                          * will be written by CPU
509                          */
510                         if (drm->mode_sync_flip ||
511                             (drm->current_front->handle->usage &
512                              GRALLOC_USAGE_SW_WRITE_MASK))
513                                 drm_kms_page_flip(drm, NULL);
514                 }
515                 break;
516         case DRM_SWAP_COPY:
517                 drm_kms_wait_for_post(drm, 0);
518                 drm->drv->blit(drm->drv, drm->current_front,
519                                 bo, 0, 0,
520                                 bo->handle->width,
521                                 bo->handle->height,
522                                 0, 0,
523                                 bo->handle->width,
524                                 bo->handle->height);
525                 if (drm->mode_quirk_vmwgfx)
526                         ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
527                 ret = 0;
528                 break;
529         case DRM_SWAP_SETCRTC:
530                 drm_kms_wait_for_post(drm, 0);
531                 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
532
533                 pthread_mutex_lock(&drm->hdmi_mutex);
534                 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
535                         drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
536                 pthread_mutex_unlock(&drm->hdmi_mutex);
537
538                 drm->current_front = bo;
539                 break;
540         default:
541                 /* no-op */
542                 ret = 0;
543                 break;
544         }
545
546         return ret;
547 }
548
549 static struct gralloc_drm_t *drm_singleton;
550
551 static void on_signal(int sig)
552 {
553         struct gralloc_drm_t *drm = drm_singleton;
554
555         /* wait the pending flip */
556         if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
557                 /* there is race, but this function is hacky enough to ignore that */
558                 if (drm_singleton->waiting_flip)
559                         usleep(100 * 1000); /* 100ms */
560                 else
561                         drm_kms_page_flip(drm_singleton, NULL);
562         }
563
564         exit(-1);
565 }
566
567 static void drm_kms_init_features(struct gralloc_drm_t *drm)
568 {
569         const char *swap_mode;
570
571         /* call to the driver here, after KMS has been initialized */
572         drm->drv->init_kms_features(drm->drv, drm);
573
574         if (drm->swap_mode == DRM_SWAP_FLIP) {
575                 struct sigaction act;
576
577                 memset(&drm->evctx, 0, sizeof(drm->evctx));
578                 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
579                 drm->evctx.page_flip_handler = page_flip_handler;
580
581                 /*
582                  * XXX GPU tends to freeze if the program is terminiated with a
583                  * flip pending.  What is the right way to handle the
584                  * situation?
585                  */
586                 sigemptyset(&act.sa_mask);
587                 act.sa_handler = on_signal;
588                 act.sa_flags = 0;
589                 sigaction(SIGINT, &act, NULL);
590                 sigaction(SIGTERM, &act, NULL);
591
592                 drm_singleton = drm;
593         }
594         else if (drm->swap_mode == DRM_SWAP_COPY) {
595                 struct gralloc_drm_bo_t *front;
596                 int stride;
597
598                 /* create the real front buffer */
599                 front = gralloc_drm_bo_create(drm,
600                                               drm->primary.mode.hdisplay,
601                                               drm->primary.mode.vdisplay,
602                                               drm->primary.fb_format,
603                                               GRALLOC_USAGE_HW_FB);
604                 if (front && gralloc_drm_bo_add_fb(front)) {
605                         gralloc_drm_bo_decref(front);
606                         front = NULL;
607                 }
608
609                 /* abuse next_front */
610                 if (front)
611                         drm->next_front = front;
612                 else
613                         drm->swap_mode = DRM_SWAP_SETCRTC;
614         }
615
616         switch (drm->swap_mode) {
617         case DRM_SWAP_FLIP:
618                 swap_mode = "flip";
619                 break;
620         case DRM_SWAP_COPY:
621                 swap_mode = "copy";
622                 break;
623         case DRM_SWAP_SETCRTC:
624                 swap_mode = "set-crtc";
625                 break;
626         default:
627                 swap_mode = "no-op";
628                 break;
629         }
630
631         ALOGD("will use %s for fb posting", swap_mode);
632 }
633
634 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
635 {
636         char value[PROPERTY_VALUE_MAX];
637         drmModeModeInfoPtr mode;
638         int dist, i;
639         int xres = 0, yres = 0;
640
641         if (property_get("debug.drm.mode", value, NULL)) {
642                 char *p = value, *end;
643
644                 /* parse <xres>x<yres>[@<bpp>] */
645                 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
646                         *bpp = 0;
647                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
648                                 xres = yres = 0;
649                 }
650
651                 if ((xres && yres) || *bpp) {
652                         ALOGI("will find the closest match for %dx%d@%d",
653                                         xres, yres, *bpp);
654                 }
655         }
656         else {
657                 *bpp = 0;
658         }
659
660         mode = NULL;
661         dist = INT_MAX;
662         for (i = 0; i < connector->count_modes; i++) {
663                 drmModeModeInfoPtr m = &connector->modes[i];
664                 int tmp;
665
666                 if (xres && yres) {
667                         tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
668                                 (m->vdisplay - yres) * (m->vdisplay - yres);
669                 }
670                 else {
671                         /* use the first preferred mode */
672                         tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
673                 }
674
675                 if (tmp < dist) {
676                         mode = m;
677                         dist = tmp;
678                         if (!dist)
679                                 break;
680                 }
681         }
682
683         /* fallback to the first mode */
684         if (!mode)
685                 mode = &connector->modes[0];
686
687         *bpp /= 8;
688
689         return mode;
690 }
691
692 /*
693  * Initialize KMS with a connector.
694  */
695 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
696                 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
697 {
698         drmModeEncoderPtr encoder;
699         drmModeModeInfoPtr mode;
700         static int used_crtcs = 0;
701         int bpp, i;
702
703         if (!connector->count_modes)
704                 return -EINVAL;
705
706         encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
707         if (!encoder)
708                 return -EINVAL;
709
710         /* find first possible crtc which is not used yet */
711         for (i = 0; i < drm->resources->count_crtcs; i++) {
712                 if (encoder->possible_crtcs & (1 << i) &&
713                         (used_crtcs & (1 << i)) != (1 << i))
714                         break;
715         }
716
717         used_crtcs |= (1 << i);
718
719         drmModeFreeEncoder(encoder);
720         if (i == drm->resources->count_crtcs)
721                 return -EINVAL;
722
723         output->bo = NULL;
724         output->crtc_id = drm->resources->crtcs[i];
725         output->connector_id = connector->connector_id;
726
727         /* print connector info */
728         if (connector->count_modes > 1) {
729                 ALOGI("there are %d modes on connector 0x%x, type %d",
730                                 connector->count_modes,
731                                 connector->connector_id,
732                                 connector->connector_type);
733                 for (i = 0; i < connector->count_modes; i++)
734                         ALOGI("  %s", connector->modes[i].name);
735         }
736         else {
737                 ALOGI("there is one mode on connector 0x%d: %s",
738                                 connector->connector_id,
739                                 connector->modes[0].name);
740         }
741
742         mode = find_mode(connector, &bpp);
743
744         ALOGI("the best mode is %s", mode->name);
745
746         output->mode = *mode;
747         switch (bpp) {
748         case 2:
749                 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
750                 break;
751         case 4:
752         default:
753                 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
754                 break;
755         }
756
757         if (connector->mmWidth && connector->mmHeight) {
758                 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
759                 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
760         }
761         else {
762                 output->xdpi = 75;
763                 output->ydpi = 75;
764         }
765
766 #ifdef DRM_MODE_FEATURE_DIRTYFB
767         drm->clip.x1 = 0;
768         drm->clip.y1 = 0;
769         drm->clip.x2 = output->mode.hdisplay;
770         drm->clip.y2 = output->mode.vdisplay;
771 #endif
772
773         return 0;
774 }
775
776
777 /*
778  * Fetch a connector of particular type
779  */
780 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
781         uint32_t type)
782 {
783         int i;
784
785         if (!drm->resources)
786                 return NULL;
787
788         for (i = 0; i < drm->resources->count_connectors; i++) {
789                 drmModeConnectorPtr connector =
790                         connector = drmModeGetConnector(drm->fd,
791                                 drm->resources->connectors[i]);
792                 if (connector) {
793                         if (connector->connector_type == type &&
794                                 connector->connection == DRM_MODE_CONNECTED)
795                                 return connector;
796                         drmModeFreeConnector(connector);
797                 }
798         }
799         return NULL;
800 }
801
802
803 /*
804  * Initializes hdmi output with a connector and allocates
805  * a private framebuffer for it. This is called on startup if
806  * hdmi cable is connected and also on hotplug events.
807  */
808 static void init_hdmi_output(struct gralloc_drm_t *drm,
809         drmModeConnectorPtr connector)
810 {
811         drm_kms_init_with_connector(drm, &drm->hdmi, connector);
812
813         ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
814                 __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
815
816         drm->hdmi.bo = gralloc_drm_bo_create(drm,
817                 drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
818                 drm->hdmi.fb_format,
819                 GRALLOC_USAGE_SW_WRITE_OFTEN|GRALLOC_USAGE_HW_RENDER);
820
821         gralloc_drm_bo_add_fb(drm->hdmi.bo);
822
823         drm->hdmi_mode = HDMI_CLONED;
824         drm->hdmi.active = 1;
825 }
826
827
828 /*
829  * Thread that listens to uevents and checks if hdmi state changes
830  */
831 static void *hdmi_observer(void *data)
832 {
833         static char uevent_desc[4096];
834         drmModeConnectorPtr hdmi;
835         struct gralloc_drm_t *drm =
836                 (struct gralloc_drm_t *) data;
837
838         uevent_init();
839
840         memset(uevent_desc, 0, sizeof(uevent_desc));
841
842         while(1) {
843
844                 /* this polls */
845                 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
846
847                 if(len && strstr(uevent_desc, "devices/virtual/switch/hdmi")) {
848
849                         /* check what changed */
850                         const char *prop = uevent_desc + strlen(uevent_desc) + 1;
851
852                         while (*prop) {
853
854                                 const char *state = strstr(prop, "SWITCH_STATE=");
855                                 if (state) {
856                                         unsigned int value = 0;
857                                         state += strlen("SWITCH_STATE=");
858                                         value = atoi(state);
859
860                                         pthread_mutex_lock(&drm->hdmi_mutex);
861
862                                         if (value) {
863                                                 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
864                                                 if (hdmi) {
865
866                                                         ALOGD("init hdmi on hotplug event");
867                                                         init_hdmi_output(drm, hdmi);
868
869                                                         /* will trigger modeset */
870                                                         drm->first_post = 1;
871
872                                                         drmModeFreeConnector(hdmi);
873
874                                                         pthread_mutex_unlock(&drm->hdmi_mutex);
875                                                 }
876                                                 break;
877                                         } else {
878                                                 drm->hdmi.active = 0;
879
880                                                 ALOGD("destroy hdmi private buffer");
881                                                 gralloc_drm_bo_decref(drm->hdmi.bo);
882                                                 drm->hdmi.bo = NULL;
883
884                                                 pthread_mutex_unlock(&drm->hdmi_mutex);
885                                                 break;
886                                         }
887
888                                         pthread_mutex_unlock(&drm->hdmi_mutex);
889                                 }
890
891                                 /* next property/value pair */
892                                 prop += strlen(prop) + 1;
893                                 if (prop - uevent_desc >= len)
894                                         break;
895                         }
896                 }
897         }
898
899         pthread_exit(NULL);
900         return 0;
901 }
902
903
904 /*
905  * Initialize KMS.
906  */
907 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
908 {
909         drmModeConnectorPtr lvds, hdmi;
910         int i, ret;
911
912         if (drm->resources)
913                 return 0;
914
915         drm->resources = drmModeGetResources(drm->fd);
916         if (!drm->resources) {
917                 ALOGE("failed to get modeset resources");
918                 return -EINVAL;
919         }
920
921         drm->plane_resources = drmModeGetPlaneResources(drm->fd);
922         if (!drm->plane_resources) {
923                 ALOGD("no planes found from drm resources");
924         } else {
925                 ALOGD("supported drm planes and formats");
926                 /* fill a helper structure for hwcomposer */
927                 drm->planes = calloc(drm->plane_resources->count_planes,
928                         sizeof(struct gralloc_drm_plane_t));
929
930                 for (i = 0; i < drm->plane_resources->count_planes; i++) {
931
932                         unsigned int j;
933
934                         drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
935                                 drm->plane_resources->planes[i]);
936
937                         ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
938                         for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
939                                 ALOGD("    format %c%c%c%c",
940                                         (drm->planes[i].drm_plane->formats[j]),
941                                         (drm->planes[i].drm_plane->formats[j])>>8,
942                                         (drm->planes[i].drm_plane->formats[j])>>16,
943                                         (drm->planes[i].drm_plane->formats[j])>>24);
944                 }
945         }
946
947         /* find the crtc/connector/mode to use */
948         lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
949         if (lvds) {
950                 drm_kms_init_with_connector(drm, &drm->primary, lvds);
951                 drmModeFreeConnector(lvds);
952                 drm->primary.active = 1;
953         }
954
955         /* if still no connector, find first connected connector and try it */
956         if (!drm->primary.active) {
957
958                 for (i = 0; i < drm->resources->count_connectors; i++) {
959                         drmModeConnectorPtr connector;
960
961                         connector = drmModeGetConnector(drm->fd,
962                                         drm->resources->connectors[i]);
963                         if (connector) {
964                                 if (connector->connection == DRM_MODE_CONNECTED) {
965                                         if (!drm_kms_init_with_connector(drm,
966                                                         &drm->primary, connector))
967                                                 break;
968                                 }
969
970                                 drmModeFreeConnector(connector);
971                         }
972                 }
973                 if (i == drm->resources->count_connectors) {
974                         ALOGE("failed to find a valid crtc/connector/mode combination");
975                         drmModeFreeResources(drm->resources);
976                         drm->resources = NULL;
977
978                         return -EINVAL;
979                 }
980         }
981
982
983         /* check if hdmi is connected already */
984         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
985         if (hdmi) {
986
987                 if (hdmi->connector_id == drm->primary.connector_id) {
988                         /* special case: our primary connector is hdmi */
989                         ALOGD("hdmi is the primary connector");
990                         goto skip_hdmi_modes;
991                 }
992
993                 ALOGD("init hdmi on startup");
994                 init_hdmi_output(drm, hdmi);
995
996                 drmModeFreeConnector(hdmi);
997         }
998
999         /* launch hdmi observer thread */
1000         pthread_mutex_init(&drm->hdmi_mutex, NULL);
1001         pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
1002
1003 skip_hdmi_modes:
1004
1005         drm_kms_init_features(drm);
1006         drm->first_post = 1;
1007
1008         return 0;
1009 }
1010
1011 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1012 {
1013         switch (drm->swap_mode) {
1014         case DRM_SWAP_FLIP:
1015                 drm_kms_page_flip(drm, NULL);
1016                 break;
1017         case DRM_SWAP_COPY:
1018                 {
1019                         struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1020                                 &drm->current_front : &drm->next_front;
1021
1022                         if (*bo)
1023                                 gralloc_drm_bo_decref(*bo);
1024                         *bo = NULL;
1025                 }
1026                 break;
1027         default:
1028                 break;
1029         }
1030
1031         /* restore crtc? */
1032
1033         if (drm->resources) {
1034                 drmModeFreeResources(drm->resources);
1035                 drm->resources = NULL;
1036         }
1037
1038         if (drm->planes) {
1039                 unsigned int i;
1040                 for (i = 0; i < drm->plane_resources->count_planes; i++)
1041                         drmModeFreePlane(drm->planes[i].drm_plane);
1042                 free(drm->planes);
1043                 drm->planes = NULL;
1044         }
1045
1046         if (drm->plane_resources) {
1047                 drmModeFreePlaneResources(drm->plane_resources);
1048                 drm->plane_resources = NULL;
1049         }
1050
1051         /* destroy private buffer of hdmi output */
1052         if (drm->hdmi.bo)
1053                 gralloc_drm_bo_decref(drm->hdmi.bo);
1054
1055         drm_singleton = NULL;
1056 }
1057
1058 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1059 {
1060         return (drm->resources != NULL);
1061 }
1062
1063 /*
1064  * Initialize a framebuffer device with KMS info.
1065  */
1066 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1067                 struct framebuffer_device_t *fb)
1068 {
1069         *((uint32_t *) &fb->flags) = 0x0;
1070         *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
1071         *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
1072         *((int *)      &fb->stride) = drm->primary.mode.hdisplay;
1073         *((float *)    &fb->fps) = drm->primary.mode.vrefresh;
1074
1075         *((int *)      &fb->format) = drm->primary.fb_format;
1076         *((float *)    &fb->xdpi) = drm->primary.xdpi;
1077         *((float *)    &fb->ydpi) = drm->primary.ydpi;
1078         *((int *)      &fb->minSwapInterval) = drm->swap_interval;
1079         *((int *)      &fb->maxSwapInterval) = drm->swap_interval;
1080 }
1081
1082 /*
1083  * Return true if fb posting is pipelined.
1084  */
1085 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1086 {
1087         return (drm->swap_mode != DRM_SWAP_SETCRTC);
1088 }