2 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3 * Copyright (C) 2010-2011 LunarG Inc.
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:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
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.
24 #define LOG_TAG "GRALLOC-KMS"
26 #include <cutils/properties.h>
27 #include <cutils/log.h>
34 #include "gralloc_drm.h"
35 #include "gralloc_drm_priv.h"
36 #include <hardware_legacy/uevent.h>
38 #include <drm_fourcc.h>
41 * Return true if a bo needs fb.
43 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
45 return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
46 bo->drm->swap_mode != DRM_SWAP_COPY);
49 static unsigned int drm_format_from_hal(int 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;
70 * Modify pitches, offsets and handles according to
71 * the format and return corresponding drm format value
73 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
74 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
76 struct gralloc_drm_t *drm = bo->drm;
78 pitches[0] = bo->handle->stride;
79 handles[0] = bo->fb_handle;
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);
86 return drm_format_from_hal(bo->handle->format);
90 * Returns planes that are supported for a particular format
92 unsigned int planes_for_format(struct gralloc_drm_t *drm,
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;
99 /* no planes available */
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);
113 * Add a fb object for a bo.
115 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
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 };
124 int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
126 if (drm_format == 0) {
127 ALOGE("error resolving drm format");
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);
138 * Remove a fb object for a bo.
140 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
143 drmModeRmFB(bo->drm->fd, bo->fb_id);
151 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
152 struct gralloc_drm_output *output, int fb_id)
156 ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
157 0, 0, &output->connector_id, 1, &output->mode);
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);
165 if (drm->mode_quirk_vmwgfx)
166 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
172 * Callback for a page flip event.
174 static void page_flip_handler(int fd, unsigned int sequence,
175 unsigned int tv_sec, unsigned int tv_usec,
178 struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
180 /* ack the last scheduled flip */
181 drm->current_front = drm->next_front;
182 drm->next_front = NULL;
188 static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
189 struct gralloc_drm_plane_t *plane)
191 struct gralloc_drm_bo_t *bo = NULL;
195 bo = gralloc_drm_bo_from_handle(plane->handle);
197 // create a framebuffer if does not exist
198 if (bo && bo->fb_id == 0) {
199 err = gralloc_drm_bo_add_fb(bo);
201 ALOGE("%s: could not create drm fb, (%s)",
202 __func__, strerror(-err));
207 err = drmModeSetPlane(drm->fd,
208 plane->drm_plane->plane_id,
209 drm->primary.crtc_id,
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;
227 ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
229 plane->drm_plane->plane_id,
230 drm->primary.crtc_id,
235 gralloc_drm_bo_decref(plane->prev);
246 * Sets all the active planes to be displayed.
248 static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
250 struct gralloc_drm_plane_t *plane = drm->planes;
252 for (i = 0; i < drm->plane_resources->count_planes;
255 * Disable overlay if it is not active
256 * or if there is error during setplane
261 if (gralloc_drm_bo_setplane(drm, plane))
267 * Interface for HWC, used to reserve a plane for a layer.
269 int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
270 buffer_handle_t handle,
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;
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);
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)) {
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;
314 /* no free planes available */
319 * Interface for HWC, used to disable all the overlays.
321 void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
323 struct gralloc_drm_plane_t *plane = drm->planes;
326 for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
332 * Schedule a page flip.
334 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
335 struct gralloc_drm_bo_t *bo)
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;
355 pthread_mutex_lock(&drm->hdmi_mutex);
356 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo) {
358 int dst_x1 = 0, dst_y1 = 0;
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;
365 drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
367 dst_x1 + bo->handle->width,
368 dst_y1 + bo->handle->height,
369 0, 0, bo->handle->width, bo->handle->height);
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);
376 pthread_mutex_unlock(&drm->hdmi_mutex);
378 /* set planes to be displayed */
379 gralloc_drm_set_planes(drm);
381 ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
382 DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
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 */
391 drm->next_front = bo;
397 * Wait for the next post.
399 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
401 unsigned int current, target;
405 if (drm->mode_quirk_vmwgfx)
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;
416 /* get the current vblank */
417 ret = drmWaitVBlank(drm->fd, &vbl);
419 ALOGW("failed to get vblank");
423 current = vbl.reply.sequence;
427 target = drm->last_swap + drm->swap_interval - flip;
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;
436 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
437 if (target < current)
441 vbl.request.sequence = target;
443 ret = drmWaitVBlank(drm->fd, &vbl);
445 ALOGW("failed to wait vblank");
450 drm->last_swap = vbl.reply.sequence + flip;
454 * Post a bo. This is not thread-safe.
456 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
458 struct gralloc_drm_t *drm = bo->drm;
461 if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
462 ALOGE("unable to post bo %p without fb", bo);
466 /* TODO spawn a thread to avoid waiting and race */
468 if (drm->first_post) {
469 if (drm->swap_mode == DRM_SWAP_COPY) {
470 struct gralloc_drm_bo_t *dst;
472 dst = (drm->next_front) ?
475 drm->drv->blit(drm->drv, dst, bo, 0, 0,
484 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
487 drm->current_front = bo;
488 if (drm->next_front == bo)
489 drm->next_front = NULL;
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);
500 switch (drm->swap_mode) {
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) {
507 * wait if the driver says so or the current front
508 * will be written by CPU
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);
517 drm_kms_wait_for_post(drm, 0);
518 drm->drv->blit(drm->drv, drm->current_front,
525 if (drm->mode_quirk_vmwgfx)
526 ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
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);
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);
538 drm->current_front = bo;
549 static struct gralloc_drm_t *drm_singleton;
551 static void on_signal(int sig)
553 struct gralloc_drm_t *drm = drm_singleton;
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 */
561 drm_kms_page_flip(drm_singleton, NULL);
567 static void drm_kms_init_features(struct gralloc_drm_t *drm)
569 const char *swap_mode;
571 /* call to the driver here, after KMS has been initialized */
572 drm->drv->init_kms_features(drm->drv, drm);
574 if (drm->swap_mode == DRM_SWAP_FLIP) {
575 struct sigaction act;
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;
582 * XXX GPU tends to freeze if the program is terminiated with a
583 * flip pending. What is the right way to handle the
586 sigemptyset(&act.sa_mask);
587 act.sa_handler = on_signal;
589 sigaction(SIGINT, &act, NULL);
590 sigaction(SIGTERM, &act, NULL);
594 else if (drm->swap_mode == DRM_SWAP_COPY) {
595 struct gralloc_drm_bo_t *front;
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);
609 /* abuse next_front */
611 drm->next_front = front;
613 drm->swap_mode = DRM_SWAP_SETCRTC;
616 switch (drm->swap_mode) {
623 case DRM_SWAP_SETCRTC:
624 swap_mode = "set-crtc";
631 ALOGD("will use %s for fb posting", swap_mode);
634 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
636 char value[PROPERTY_VALUE_MAX];
637 drmModeModeInfoPtr mode;
639 int xres = 0, yres = 0;
641 if (property_get("debug.drm.mode", value, NULL)) {
642 char *p = value, *end;
644 /* parse <xres>x<yres>[@<bpp>] */
645 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
647 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
651 if ((xres && yres) || *bpp) {
652 ALOGI("will find the closest match for %dx%d@%d",
662 for (i = 0; i < connector->count_modes; i++) {
663 drmModeModeInfoPtr m = &connector->modes[i];
667 tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
668 (m->vdisplay - yres) * (m->vdisplay - yres);
671 /* use the first preferred mode */
672 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
683 /* fallback to the first mode */
685 mode = &connector->modes[0];
693 * Initialize KMS with a connector.
695 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
696 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
698 drmModeEncoderPtr encoder;
699 drmModeModeInfoPtr mode;
700 static int used_crtcs = 0;
703 if (!connector->count_modes)
706 encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
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))
717 used_crtcs |= (1 << i);
719 drmModeFreeEncoder(encoder);
720 if (i == drm->resources->count_crtcs)
724 output->crtc_id = drm->resources->crtcs[i];
725 output->connector_id = connector->connector_id;
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);
737 ALOGI("there is one mode on connector 0x%d: %s",
738 connector->connector_id,
739 connector->modes[0].name);
742 mode = find_mode(connector, &bpp);
744 ALOGI("the best mode is %s", mode->name);
746 output->mode = *mode;
749 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
753 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
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);
766 #ifdef DRM_MODE_FEATURE_DIRTYFB
769 drm->clip.x2 = output->mode.hdisplay;
770 drm->clip.y2 = output->mode.vdisplay;
778 * Fetch a connector of particular type
780 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
788 for (i = 0; i < drm->resources->count_connectors; i++) {
789 drmModeConnectorPtr connector =
790 connector = drmModeGetConnector(drm->fd,
791 drm->resources->connectors[i]);
793 if (connector->connector_type == type &&
794 connector->connection == DRM_MODE_CONNECTED)
796 drmModeFreeConnector(connector);
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.
808 static void init_hdmi_output(struct gralloc_drm_t *drm,
809 drmModeConnectorPtr connector)
811 drm_kms_init_with_connector(drm, &drm->hdmi, connector);
813 ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
814 __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
816 drm->hdmi.bo = gralloc_drm_bo_create(drm,
817 drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
819 GRALLOC_USAGE_SW_WRITE_OFTEN|GRALLOC_USAGE_HW_RENDER);
821 gralloc_drm_bo_add_fb(drm->hdmi.bo);
823 drm->hdmi_mode = HDMI_CLONED;
824 drm->hdmi.active = 1;
829 * Thread that listens to uevents and checks if hdmi state changes
831 static void *hdmi_observer(void *data)
833 static char uevent_desc[4096];
834 drmModeConnectorPtr hdmi;
835 struct gralloc_drm_t *drm =
836 (struct gralloc_drm_t *) data;
840 memset(uevent_desc, 0, sizeof(uevent_desc));
845 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
847 if(len && strstr(uevent_desc, "devices/virtual/switch/hdmi")) {
849 /* check what changed */
850 const char *prop = uevent_desc + strlen(uevent_desc) + 1;
854 const char *state = strstr(prop, "SWITCH_STATE=");
856 unsigned int value = 0;
857 state += strlen("SWITCH_STATE=");
860 pthread_mutex_lock(&drm->hdmi_mutex);
863 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
866 ALOGD("init hdmi on hotplug event");
867 init_hdmi_output(drm, hdmi);
869 /* will trigger modeset */
872 drmModeFreeConnector(hdmi);
874 pthread_mutex_unlock(&drm->hdmi_mutex);
878 drm->hdmi.active = 0;
880 ALOGD("destroy hdmi private buffer");
881 gralloc_drm_bo_decref(drm->hdmi.bo);
884 pthread_mutex_unlock(&drm->hdmi_mutex);
888 pthread_mutex_unlock(&drm->hdmi_mutex);
891 /* next property/value pair */
892 prop += strlen(prop) + 1;
893 if (prop - uevent_desc >= len)
907 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
909 drmModeConnectorPtr lvds, hdmi;
915 drm->resources = drmModeGetResources(drm->fd);
916 if (!drm->resources) {
917 ALOGE("failed to get modeset resources");
921 drm->plane_resources = drmModeGetPlaneResources(drm->fd);
922 if (!drm->plane_resources) {
923 ALOGD("no planes found from drm resources");
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));
930 for (i = 0; i < drm->plane_resources->count_planes; i++) {
934 drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
935 drm->plane_resources->planes[i]);
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);
947 /* find the crtc/connector/mode to use */
948 lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
950 drm_kms_init_with_connector(drm, &drm->primary, lvds);
951 drmModeFreeConnector(lvds);
952 drm->primary.active = 1;
955 /* if still no connector, find first connected connector and try it */
956 if (!drm->primary.active) {
958 for (i = 0; i < drm->resources->count_connectors; i++) {
959 drmModeConnectorPtr connector;
961 connector = drmModeGetConnector(drm->fd,
962 drm->resources->connectors[i]);
964 if (connector->connection == DRM_MODE_CONNECTED) {
965 if (!drm_kms_init_with_connector(drm,
966 &drm->primary, connector))
970 drmModeFreeConnector(connector);
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;
983 /* check if hdmi is connected already */
984 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
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;
993 ALOGD("init hdmi on startup");
994 init_hdmi_output(drm, hdmi);
996 drmModeFreeConnector(hdmi);
999 /* launch hdmi observer thread */
1000 pthread_mutex_init(&drm->hdmi_mutex, NULL);
1001 pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
1005 drm_kms_init_features(drm);
1006 drm->first_post = 1;
1011 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1013 switch (drm->swap_mode) {
1015 drm_kms_page_flip(drm, NULL);
1019 struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1020 &drm->current_front : &drm->next_front;
1023 gralloc_drm_bo_decref(*bo);
1033 if (drm->resources) {
1034 drmModeFreeResources(drm->resources);
1035 drm->resources = NULL;
1040 for (i = 0; i < drm->plane_resources->count_planes; i++)
1041 drmModeFreePlane(drm->planes[i].drm_plane);
1046 if (drm->plane_resources) {
1047 drmModeFreePlaneResources(drm->plane_resources);
1048 drm->plane_resources = NULL;
1051 /* destroy private buffer of hdmi output */
1053 gralloc_drm_bo_decref(drm->hdmi.bo);
1055 drm_singleton = NULL;
1058 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1060 return (drm->resources != NULL);
1064 * Initialize a framebuffer device with KMS info.
1066 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1067 struct framebuffer_device_t *fb)
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;
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;
1083 * Return true if fb posting is pipelined.
1085 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1087 return (drm->swap_mode != DRM_SWAP_SETCRTC);