OSDN Git Service

gralloc: implement yuv offset query as hw specific function
[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  * Add a fb object for a bo.
91  */
92 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
93 {
94         uint32_t pitches[4] = { 0, 0, 0, 0 };
95         uint32_t offsets[4] = { 0, 0, 0, 0 };
96         uint32_t handles[4] = { 0, 0, 0, 0 };
97
98         if (bo->fb_id)
99                 return 0;
100
101         int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
102
103         if (drm_format == 0) {
104                 ALOGE("error resolving drm format");
105                 return -EINVAL;
106         }
107
108         return drmModeAddFB2(bo->drm->fd,
109                 bo->handle->width, bo->handle->height,
110                 drm_format, handles, pitches, offsets,
111                 (uint32_t *) &bo->fb_id, 0);
112 }
113
114 /*
115  * Remove a fb object for a bo.
116  */
117 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
118 {
119         if (bo->fb_id) {
120                 drmModeRmFB(bo->drm->fd, bo->fb_id);
121                 bo->fb_id = 0;
122         }
123 }
124
125 /*
126  * Program CRTC.
127  */
128 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
129         struct gralloc_drm_output *output, int fb_id)
130 {
131         int ret;
132
133         ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
134                         0, 0, &output->connector_id, 1, &output->mode);
135         if (ret) {
136                 ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
137                         strerror(errno), output->crtc_id, fb_id, output->connector_id,
138                         output->mode.hdisplay, output->mode.vdisplay);
139                 return ret;
140         }
141
142         if (drm->mode_quirk_vmwgfx)
143                 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
144
145         return ret;
146 }
147
148 /*
149  * Callback for a page flip event.
150  */
151 static void page_flip_handler(int fd, unsigned int sequence,
152                 unsigned int tv_sec, unsigned int tv_usec,
153                 void *user_data)
154 {
155         struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
156
157         /* ack the last scheduled flip */
158         drm->current_front = drm->next_front;
159         drm->next_front = NULL;
160 }
161
162 /*
163  * Schedule a page flip.
164  */
165 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
166                 struct gralloc_drm_bo_t *bo)
167 {
168         int ret;
169
170         /* there is another flip pending */
171         while (drm->next_front) {
172                 drm->waiting_flip = 1;
173                 drmHandleEvent(drm->fd, &drm->evctx);
174                 drm->waiting_flip = 0;
175                 if (drm->next_front) {
176                         /* record an error and break */
177                         ALOGE("drmHandleEvent returned without flipping");
178                         drm->current_front = drm->next_front;
179                         drm->next_front = NULL;
180                 }
181         }
182
183         if (!bo)
184                 return 0;
185
186         pthread_mutex_lock(&drm->hdmi_mutex);
187         if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED) {
188                 ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, bo->fb_id, 0, NULL);
189                 if (ret && errno != EBUSY)
190                         ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
191                                 strerror(errno), drm->hdmi.crtc_id, bo->fb_id);
192         }
193         pthread_mutex_unlock(&drm->hdmi_mutex);
194
195         ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
196                         DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
197         if (ret) {
198                 ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
199                         strerror(errno), drm->primary.crtc_id, bo->fb_id);
200                 /* try to set mode for next frame */
201                 if (errno != EBUSY)
202                         drm->first_post = 1;
203         }
204         else
205                 drm->next_front = bo;
206
207         return ret;
208 }
209
210 /*
211  * Wait for the next post.
212  */
213 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
214 {
215         unsigned int current, target;
216         drmVBlank vbl;
217         int ret;
218
219         if (drm->mode_quirk_vmwgfx)
220                 return;
221
222         flip = !!flip;
223
224         memset(&vbl, 0, sizeof(vbl));
225         vbl.request.type = DRM_VBLANK_RELATIVE;
226         if (drm->vblank_secondary)
227                 vbl.request.type |= DRM_VBLANK_SECONDARY;
228         vbl.request.sequence = 0;
229
230         /* get the current vblank */
231         ret = drmWaitVBlank(drm->fd, &vbl);
232         if (ret) {
233                 ALOGW("failed to get vblank");
234                 return;
235         }
236
237         current = vbl.reply.sequence;
238         if (drm->first_post)
239                 target = current;
240         else
241                 target = drm->last_swap + drm->swap_interval - flip;
242
243         /* wait for vblank */
244         if (current < target || !flip) {
245                 memset(&vbl, 0, sizeof(vbl));
246                 vbl.request.type = DRM_VBLANK_ABSOLUTE;
247                 if (drm->vblank_secondary)
248                         vbl.request.type |= DRM_VBLANK_SECONDARY;
249                 if (!flip) {
250                         vbl.request.type |= DRM_VBLANK_NEXTONMISS;
251                         if (target < current)
252                                 target = current;
253                 }
254
255                 vbl.request.sequence = target;
256
257                 ret = drmWaitVBlank(drm->fd, &vbl);
258                 if (ret) {
259                         ALOGW("failed to wait vblank");
260                         return;
261                 }
262         }
263
264         drm->last_swap = vbl.reply.sequence + flip;
265 }
266
267 /*
268  * Post a bo.  This is not thread-safe.
269  */
270 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
271 {
272         struct gralloc_drm_t *drm = bo->drm;
273         int ret;
274
275         if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
276                 ALOGE("unable to post bo %p without fb", bo);
277                 return -EINVAL;
278         }
279
280         /* TODO spawn a thread to avoid waiting and race */
281
282         if (drm->first_post) {
283                 if (drm->swap_mode == DRM_SWAP_COPY) {
284                         struct gralloc_drm_bo_t *dst;
285
286                         dst = (drm->next_front) ?
287                                 drm->next_front :
288                                 drm->current_front;
289                         drm->drv->copy(drm->drv, dst, bo, 0, 0,
290                                         bo->handle->width,
291                                         bo->handle->height);
292                         bo = dst;
293                 }
294
295                 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
296                 if (!ret) {
297                         drm->first_post = 0;
298                         drm->current_front = bo;
299                         if (drm->next_front == bo)
300                                 drm->next_front = NULL;
301                 }
302
303                 pthread_mutex_lock(&drm->hdmi_mutex);
304                 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED)
305                         drm_kms_set_crtc(drm, &drm->hdmi, bo->fb_id);
306                 pthread_mutex_unlock(&drm->hdmi_mutex);
307
308                 return ret;
309         }
310
311         switch (drm->swap_mode) {
312         case DRM_SWAP_FLIP:
313                 if (drm->swap_interval > 1)
314                         drm_kms_wait_for_post(drm, 1);
315                 ret = drm_kms_page_flip(drm, bo);
316                 if (drm->next_front) {
317                         /*
318                          * wait if the driver says so or the current front
319                          * will be written by CPU
320                          */
321                         if (drm->mode_sync_flip ||
322                             (drm->current_front->handle->usage &
323                              GRALLOC_USAGE_SW_WRITE_MASK))
324                                 drm_kms_page_flip(drm, NULL);
325                 }
326                 break;
327         case DRM_SWAP_COPY:
328                 drm_kms_wait_for_post(drm, 0);
329                 drm->drv->copy(drm->drv, drm->current_front,
330                                 bo, 0, 0,
331                                 bo->handle->width,
332                                 bo->handle->height);
333                 if (drm->mode_quirk_vmwgfx)
334                         ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
335                 ret = 0;
336                 break;
337         case DRM_SWAP_SETCRTC:
338                 drm_kms_wait_for_post(drm, 0);
339                 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
340
341                 pthread_mutex_lock(&drm->hdmi_mutex);
342                 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED)
343                         drm_kms_set_crtc(drm, &drm->hdmi, bo->fb_id);
344                 pthread_mutex_unlock(&drm->hdmi_mutex);
345
346                 drm->current_front = bo;
347                 break;
348         default:
349                 /* no-op */
350                 ret = 0;
351                 break;
352         }
353
354         return ret;
355 }
356
357 static struct gralloc_drm_t *drm_singleton;
358
359 static void on_signal(int sig)
360 {
361         struct gralloc_drm_t *drm = drm_singleton;
362
363         /* wait the pending flip */
364         if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
365                 /* there is race, but this function is hacky enough to ignore that */
366                 if (drm_singleton->waiting_flip)
367                         usleep(100 * 1000); /* 100ms */
368                 else
369                         drm_kms_page_flip(drm_singleton, NULL);
370         }
371
372         exit(-1);
373 }
374
375 static void drm_kms_init_features(struct gralloc_drm_t *drm)
376 {
377         const char *swap_mode;
378
379         /* call to the driver here, after KMS has been initialized */
380         drm->drv->init_kms_features(drm->drv, drm);
381
382         if (drm->swap_mode == DRM_SWAP_FLIP) {
383                 struct sigaction act;
384
385                 memset(&drm->evctx, 0, sizeof(drm->evctx));
386                 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
387                 drm->evctx.page_flip_handler = page_flip_handler;
388
389                 /*
390                  * XXX GPU tends to freeze if the program is terminiated with a
391                  * flip pending.  What is the right way to handle the
392                  * situation?
393                  */
394                 sigemptyset(&act.sa_mask);
395                 act.sa_handler = on_signal;
396                 act.sa_flags = 0;
397                 sigaction(SIGINT, &act, NULL);
398                 sigaction(SIGTERM, &act, NULL);
399
400                 drm_singleton = drm;
401         }
402         else if (drm->swap_mode == DRM_SWAP_COPY) {
403                 struct gralloc_drm_bo_t *front;
404                 int stride;
405
406                 /* create the real front buffer */
407                 front = gralloc_drm_bo_create(drm,
408                                               drm->primary.mode.hdisplay,
409                                               drm->primary.mode.vdisplay,
410                                               drm->primary.fb_format,
411                                               GRALLOC_USAGE_HW_FB);
412                 if (front && gralloc_drm_bo_add_fb(front)) {
413                         gralloc_drm_bo_decref(front);
414                         front = NULL;
415                 }
416
417                 /* abuse next_front */
418                 if (front)
419                         drm->next_front = front;
420                 else
421                         drm->swap_mode = DRM_SWAP_SETCRTC;
422         }
423
424         switch (drm->swap_mode) {
425         case DRM_SWAP_FLIP:
426                 swap_mode = "flip";
427                 break;
428         case DRM_SWAP_COPY:
429                 swap_mode = "copy";
430                 break;
431         case DRM_SWAP_SETCRTC:
432                 swap_mode = "set-crtc";
433                 break;
434         default:
435                 swap_mode = "no-op";
436                 break;
437         }
438
439         ALOGD("will use %s for fb posting", swap_mode);
440 }
441
442 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
443 {
444         char value[PROPERTY_VALUE_MAX];
445         drmModeModeInfoPtr mode;
446         int dist, i;
447         int xres = 0, yres = 0;
448
449         if (property_get("debug.drm.mode", value, NULL)) {
450                 char *p = value, *end;
451
452                 /* parse <xres>x<yres>[@<bpp>] */
453                 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
454                         *bpp = 0;
455                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
456                                 xres = yres = 0;
457                 }
458
459                 if ((xres && yres) || *bpp) {
460                         ALOGI("will find the closest match for %dx%d@%d",
461                                         xres, yres, *bpp);
462                 }
463         }
464         else {
465                 *bpp = 0;
466         }
467
468         mode = NULL;
469         dist = INT_MAX;
470         for (i = 0; i < connector->count_modes; i++) {
471                 drmModeModeInfoPtr m = &connector->modes[i];
472                 int tmp;
473
474                 if (xres && yres) {
475                         tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
476                                 (m->vdisplay - yres) * (m->vdisplay - yres);
477                 }
478                 else {
479                         /* use the first preferred mode */
480                         tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
481                 }
482
483                 if (tmp < dist) {
484                         mode = m;
485                         dist = tmp;
486                         if (!dist)
487                                 break;
488                 }
489         }
490
491         /* fallback to the first mode */
492         if (!mode)
493                 mode = &connector->modes[0];
494
495         *bpp /= 8;
496
497         return mode;
498 }
499
500 /*
501  * Initialize KMS with a connector.
502  */
503 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
504                 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
505 {
506         drmModeEncoderPtr encoder;
507         drmModeModeInfoPtr mode;
508         static int used_crtcs = 0;
509         int bpp, i;
510
511         if (!connector->count_modes)
512                 return -EINVAL;
513
514         encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
515         if (!encoder)
516                 return -EINVAL;
517
518         /* find first possible crtc which is not used yet */
519         for (i = 0; i < drm->resources->count_crtcs; i++) {
520                 if (encoder->possible_crtcs & (1 << i) &&
521                         (used_crtcs & (1 << i)) != (1 << i))
522                         break;
523         }
524
525         used_crtcs |= (1 << i);
526
527         drmModeFreeEncoder(encoder);
528         if (i == drm->resources->count_crtcs)
529                 return -EINVAL;
530
531         output->crtc_id = drm->resources->crtcs[i];
532         output->connector_id = connector->connector_id;
533
534         /* print connector info */
535         if (connector->count_modes > 1) {
536                 ALOGI("there are %d modes on connector 0x%x",
537                                 connector->count_modes,
538                                 connector->connector_id);
539                 for (i = 0; i < connector->count_modes; i++)
540                         ALOGI("  %s", connector->modes[i].name);
541         }
542         else {
543                 ALOGI("there is one mode on connector 0x%d: %s",
544                                 connector->connector_id,
545                                 connector->modes[0].name);
546         }
547
548         mode = find_mode(connector, &bpp);
549
550         ALOGI("the best mode is %s", mode->name);
551
552         output->mode = *mode;
553         switch (bpp) {
554         case 2:
555                 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
556                 break;
557         case 4:
558         default:
559                 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
560                 break;
561         }
562
563         if (connector->mmWidth && connector->mmHeight) {
564                 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
565                 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
566         }
567         else {
568                 output->xdpi = 75;
569                 output->ydpi = 75;
570         }
571
572 #ifdef DRM_MODE_FEATURE_DIRTYFB
573         drm->clip.x1 = 0;
574         drm->clip.y1 = 0;
575         drm->clip.x2 = output->mode.hdisplay;
576         drm->clip.y2 = output->mode.vdisplay;
577 #endif
578
579         return 0;
580 }
581
582
583 /*
584  * Fetch a connector of particular type
585  */
586 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
587         uint32_t type)
588 {
589         int i;
590
591         if (!drm->resources)
592                 return NULL;
593
594         for (i = 0; i < drm->resources->count_connectors; i++) {
595                 drmModeConnectorPtr connector =
596                         connector = drmModeGetConnector(drm->fd,
597                                 drm->resources->connectors[i]);
598                 if (connector) {
599                         if (connector->connector_type == type &&
600                                 connector->connection == DRM_MODE_CONNECTED)
601                                 return connector;
602                         drmModeFreeConnector(connector);
603                 }
604         }
605         return NULL;
606 }
607
608
609 /*
610  * Thread that listens to uevents and checks if hdmi state changes
611  */
612 static void *hdmi_observer(void *data)
613 {
614         static char uevent_desc[4096];
615         drmModeConnectorPtr hdmi;
616         struct gralloc_drm_t *drm =
617                 (struct gralloc_drm_t *) data;
618
619         uevent_init();
620
621         memset(uevent_desc, 0, sizeof(uevent_desc));
622
623         while(1) {
624
625                 /* this polls */
626                 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
627
628                 if(len && strstr(uevent_desc, "devices/virtual/switch/hdmi")) {
629
630                         /* check what changed */
631                         const char *prop = uevent_desc + strlen(uevent_desc) + 1;
632
633                         while (*prop) {
634
635                                 const char *state = strstr(prop, "SWITCH_STATE=");
636                                 if (state) {
637                                         unsigned int value = 0;
638                                         state += strlen("SWITCH_STATE=");
639                                         value = atoi(state);
640
641                                         pthread_mutex_lock(&drm->hdmi_mutex);
642
643                                         if (value) {
644                                                 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
645                                                 if (hdmi) {
646                                                         drm_kms_init_with_connector(drm, &drm->hdmi, hdmi);
647                                                         drmModeFreeConnector(hdmi);
648
649                                                         /* will trigger modeset */
650                                                         drm->first_post = 1;
651
652                                                         /* HACK, assume same mode for now */
653                                                         memcpy(&drm->hdmi.mode, &drm->primary.mode,
654                                                                 sizeof(drmModeModeInfo));
655
656                                                         drm->hdmi_mode = HDMI_CLONED;
657                                                         drm->hdmi.active = 1;
658                                                         pthread_mutex_unlock(&drm->hdmi_mutex);
659                                                 }
660                                                 break;
661                                         } else {
662                                                 drm->hdmi.active = 0;
663                                                 pthread_mutex_unlock(&drm->hdmi_mutex);
664                                                 break;
665                                         }
666
667                                         pthread_mutex_unlock(&drm->hdmi_mutex);
668                                 }
669
670                                 /* next property/value pair */
671                                 prop += strlen(prop) + 1;
672                                 if (prop - uevent_desc >= len)
673                                         break;
674                         }
675                 }
676         }
677
678         pthread_exit(NULL);
679         return 0;
680 }
681
682
683 /*
684  * Initialize KMS.
685  */
686 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
687 {
688         drmModeConnectorPtr lvds, hdmi;
689         int i, ret;
690
691         if (drm->resources)
692                 return 0;
693
694         drm->resources = drmModeGetResources(drm->fd);
695         if (!drm->resources) {
696                 ALOGE("failed to get modeset resources");
697                 return -EINVAL;
698         }
699
700         drm->plane_resources = drmModeGetPlaneResources(drm->fd);
701         if (!drm->plane_resources) {
702                 ALOGD("no planes found from drm resources");
703         } else {
704                 ALOGD("supported drm planes and formats");
705                 /* fill a helper structure for hwcomposer */
706                 drm->planes = calloc(drm->plane_resources->count_planes,
707                         sizeof(struct gralloc_drm_plane_t));
708
709                 for (i = 0; i < drm->plane_resources->count_planes; i++) {
710
711                         unsigned int j;
712
713                         drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
714                                 drm->plane_resources->planes[i]);
715
716                         ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
717                         for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
718                                 ALOGD("    format %c%c%c%c",
719                                         (drm->planes[i].drm_plane->formats[j]),
720                                         (drm->planes[i].drm_plane->formats[j])>>8,
721                                         (drm->planes[i].drm_plane->formats[j])>>16,
722                                         (drm->planes[i].drm_plane->formats[j])>>24);
723                 }
724         }
725
726         /* find the crtc/connector/mode to use */
727         lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
728         if (lvds) {
729                 drm_kms_init_with_connector(drm, &drm->primary, lvds);
730                 drmModeFreeConnector(lvds);
731                 drm->primary.active = 1;
732         }
733
734         /* if still no connector, find first connected connector and try it */
735         if (!drm->primary.active) {
736
737                 for (i = 0; i < drm->resources->count_connectors; i++) {
738                         drmModeConnectorPtr connector;
739
740                         connector = drmModeGetConnector(drm->fd,
741                                         drm->resources->connectors[i]);
742                         if (connector) {
743                                 if (connector->connection == DRM_MODE_CONNECTED) {
744                                         if (!drm_kms_init_with_connector(drm,
745                                                         &drm->primary, connector))
746                                                 break;
747                                 }
748
749                                 drmModeFreeConnector(connector);
750                         }
751                 }
752                 if (i == drm->resources->count_connectors) {
753                         ALOGE("failed to find a valid crtc/connector/mode combination");
754                         drmModeFreeResources(drm->resources);
755                         drm->resources = NULL;
756
757                         return -EINVAL;
758                 }
759         }
760
761         /* check if hdmi is connected already */
762         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
763         if (hdmi) {
764
765                 if (hdmi->connector_id == drm->primary.connector_id) {
766                         /* special case: our primary connector is hdmi */
767                         goto skip_hdmi_modes;
768                 }
769
770                 drm_kms_init_with_connector(drm, &drm->hdmi, hdmi);
771                 drmModeFreeConnector(hdmi);
772
773                 /* HACK, assume same mode for now */
774                 memcpy(&drm->hdmi.mode, &drm->primary.mode,
775                         sizeof(drmModeModeInfo));
776
777                 drm->hdmi_mode = HDMI_CLONED;
778                 drm->hdmi.active = 1;
779         }
780
781         /* launch hdmi observer thread */
782         pthread_mutex_init(&drm->hdmi_mutex, NULL);
783         pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
784
785 skip_hdmi_modes:
786
787         drm_kms_init_features(drm);
788         drm->first_post = 1;
789
790         return 0;
791 }
792
793 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
794 {
795         switch (drm->swap_mode) {
796         case DRM_SWAP_FLIP:
797                 drm_kms_page_flip(drm, NULL);
798                 break;
799         case DRM_SWAP_COPY:
800                 {
801                         struct gralloc_drm_bo_t **bo = (drm->current_front) ?
802                                 &drm->current_front : &drm->next_front;
803
804                         if (*bo)
805                                 gralloc_drm_bo_decref(*bo);
806                         *bo = NULL;
807                 }
808                 break;
809         default:
810                 break;
811         }
812
813         /* restore crtc? */
814
815         if (drm->resources) {
816                 drmModeFreeResources(drm->resources);
817                 drm->resources = NULL;
818         }
819
820         if (drm->planes) {
821                 unsigned int i;
822                 for (i = 0; i < drm->plane_resources->count_planes; i++)
823                         drmModeFreePlane(drm->planes[i].drm_plane);
824                 free(drm->planes);
825                 drm->planes = NULL;
826         }
827
828         if (drm->plane_resources) {
829                 drmModeFreePlaneResources(drm->plane_resources);
830                 drm->plane_resources = NULL;
831         }
832
833         drm_singleton = NULL;
834 }
835
836 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
837 {
838         return (drm->resources != NULL);
839 }
840
841 /*
842  * Initialize a framebuffer device with KMS info.
843  */
844 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
845                 struct framebuffer_device_t *fb)
846 {
847         *((uint32_t *) &fb->flags) = 0x0;
848         *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
849         *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
850         *((int *)      &fb->stride) = drm->primary.mode.hdisplay;
851         *((float *)    &fb->fps) = drm->primary.mode.vrefresh;
852
853         *((int *)      &fb->format) = drm->primary.fb_format;
854         *((float *)    &fb->xdpi) = drm->primary.xdpi;
855         *((float *)    &fb->ydpi) = drm->primary.ydpi;
856         *((int *)      &fb->minSwapInterval) = drm->swap_interval;
857         *((int *)      &fb->maxSwapInterval) = drm->swap_interval;
858 }
859
860 /*
861  * Return true if fb posting is pipelined.
862  */
863 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
864 {
865         return (drm->swap_mode != DRM_SWAP_SETCRTC);
866 }