OSDN Git Service

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