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>
35 #include "gralloc_drm.h"
36 #include "gralloc_drm_priv.h"
37 #include <hardware_legacy/uevent.h>
39 #include <drm_fourcc.h>
42 * Return true if a bo needs fb.
44 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
46 return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
47 bo->drm->swap_mode != DRM_SWAP_COPY);
50 static unsigned int drm_format_from_hal(int hal_format)
53 case HAL_PIXEL_FORMAT_RGB_888:
54 case HAL_PIXEL_FORMAT_BGRA_8888:
55 return DRM_FORMAT_XRGB8888;
56 case HAL_PIXEL_FORMAT_RGBX_8888:
57 return DRM_FORMAT_XBGR8888;
58 case HAL_PIXEL_FORMAT_RGBA_8888:
59 return DRM_FORMAT_RGBA8888;
60 case HAL_PIXEL_FORMAT_RGB_565:
61 return DRM_FORMAT_RGB565;
62 case HAL_PIXEL_FORMAT_YV12:
63 return DRM_FORMAT_YUV420;
64 case HAL_PIXEL_FORMAT_DRM_NV12:
65 return DRM_FORMAT_NV12;
72 * Modify pitches, offsets and handles according to
73 * the format and return corresponding drm format value
75 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
76 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
78 struct gralloc_drm_t *drm = bo->drm;
80 pitches[0] = bo->handle->stride;
81 handles[0] = bo->fb_handle;
83 /* driver takes care of HW specific padding, alignment etc. */
84 if (drm->drv->resolve_format)
85 drm->drv->resolve_format(drm->drv, bo,
86 pitches, offsets, handles);
88 return drm_format_from_hal(bo->handle->format);
92 * Returns planes that are supported for a particular format
94 unsigned int planes_for_format(struct gralloc_drm_t *drm,
97 unsigned int i, j, mask = 0;
98 unsigned int drm_format = drm_format_from_hal(hal_format);
99 struct gralloc_drm_plane_t *plane = drm->planes;
101 /* no planes available */
105 /* iterate through planes, mark those that match format */
106 for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
107 for (j=0; j<plane->drm_plane->count_formats; j++)
108 if (plane->drm_plane->formats[j] == drm_format)
109 mask |= (1U << plane->drm_plane->plane_id);
115 * Add a fb object for a bo.
117 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
119 uint32_t pitches[4] = { 0, 0, 0, 0 };
120 uint32_t offsets[4] = { 0, 0, 0, 0 };
121 uint32_t handles[4] = { 0, 0, 0, 0 };
126 int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
128 if (drm_format == 0) {
129 ALOGE("error resolving drm format");
133 return drmModeAddFB2(bo->drm->fd,
134 bo->handle->width, bo->handle->height,
135 drm_format, handles, pitches, offsets,
136 (uint32_t *) &bo->fb_id, 0);
140 * Remove a fb object for a bo.
142 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
145 drmModeRmFB(bo->drm->fd, bo->fb_id);
153 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
154 struct gralloc_drm_output *output, int fb_id)
158 ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
159 0, 0, &output->connector_id, 1, &output->mode);
161 ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
162 strerror(errno), output->crtc_id, fb_id, output->connector_id,
163 output->mode.hdisplay, output->mode.vdisplay);
167 if (drm->mode_quirk_vmwgfx)
168 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
174 * Callback for a page flip event.
176 static void page_flip_handler(int fd, unsigned int sequence,
177 unsigned int tv_sec, unsigned int tv_usec,
180 struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
182 /* ack the last scheduled flip */
183 drm->current_front = drm->next_front;
184 drm->next_front = NULL;
190 static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
191 struct gralloc_drm_plane_t *plane)
193 struct gralloc_drm_bo_t *bo = NULL;
197 bo = gralloc_drm_bo_from_handle(plane->handle);
199 // create a framebuffer if does not exist
200 if (bo && bo->fb_id == 0) {
201 err = gralloc_drm_bo_add_fb(bo);
203 ALOGE("%s: could not create drm fb, (%s)",
204 __func__, strerror(-err));
209 err = drmModeSetPlane(drm->fd,
210 plane->drm_plane->plane_id,
211 drm->primary.crtc_id,
224 /* clear plane_mask so that this buffer won't be tried again */
225 struct gralloc_drm_handle_t *drm_handle =
226 (struct gralloc_drm_handle_t *) plane->handle;
227 drm_handle->plane_mask = 0;
229 ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
231 plane->drm_plane->plane_id,
232 drm->primary.crtc_id,
237 gralloc_drm_bo_decref(plane->prev);
248 * Returns if a particular plane is supported with the implementation
250 static unsigned is_plane_supported(const struct gralloc_drm_t *drm,
251 const struct gralloc_drm_plane_t *plane)
253 /* Planes are only supported on primary pipe for now */
254 return plane->drm_plane->possible_crtcs & (1 << drm->primary.pipe);
258 * Sets all the active planes to be displayed.
260 static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
262 struct gralloc_drm_plane_t *plane = drm->planes;
264 for (i = 0; i < drm->plane_resources->count_planes;
266 /* plane is not in use at all */
267 if (!plane->active && !plane->handle)
270 /* plane is active, safety check if it is supported */
271 if (!is_plane_supported(drm, plane))
272 ALOGE("%s: plane %d is not supported",
273 __func__, plane->drm_plane->plane_id);
276 * Disable overlay if it is not active
277 * or if there is error during setplane
282 if (gralloc_drm_bo_setplane(drm, plane))
288 * Interface for HWC, used to reserve a plane for a layer.
290 int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
291 buffer_handle_t handle,
303 struct gralloc_drm_handle_t *drm_handle =
304 gralloc_drm_handle(handle);
305 int plane_count = drm->plane_resources->count_planes;
306 struct gralloc_drm_plane_t *plane = drm->planes;
308 /* no supported planes for this handle */
309 if (!drm_handle->plane_mask) {
310 ALOGE("%s: buffer %p cannot be shown on a plane\n",
311 __func__, drm_handle);
315 for (j = 0; j < plane_count; j++, plane++) {
318 * handle may be suitable to be shown on a plane, in
319 * addition we need to check that this particular plane
320 * is supported by the current implementation
322 if (!is_plane_supported(drm, plane))
325 /* if plane is available and can support this buffer */
326 if (!plane->active &&
327 drm_handle->plane_mask &
328 (1U << plane->drm_plane->plane_id)) {
330 plane->dst_x = dst_x;
331 plane->dst_y = dst_y;
332 plane->dst_w = dst_w;
333 plane->dst_h = dst_h;
334 plane->src_x = src_x;
335 plane->src_y = src_y;
336 plane->src_w = src_w;
337 plane->src_h = src_h;
338 plane->handle = handle;
346 /* no free planes available */
351 * Interface for HWC, used to disable all the overlays. Plane id
352 * is also set to 0 as it should be mappable to a particular layer only
353 * if it has been reserved with 'reserve_plane'.
355 void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
357 struct gralloc_drm_plane_t *plane = drm->planes;
360 for (i = 0; i < drm->plane_resources->count_planes; i++, plane++) {
367 * Interface for HWC, used to change handle of a reserved plane.
369 int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
370 uint32_t id, buffer_handle_t handle)
372 struct gralloc_drm_plane_t *plane = drm->planes;
375 for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
376 if (plane->active && plane->id == id) {
377 plane->handle = handle;
385 * Schedule a page flip.
387 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
388 struct gralloc_drm_bo_t *bo)
392 /* there is another flip pending */
393 while (drm->next_front) {
394 drm->waiting_flip = 1;
395 drmHandleEvent(drm->fd, &drm->evctx);
396 drm->waiting_flip = 0;
397 if (drm->next_front) {
398 /* record an error and break */
399 ALOGE("drmHandleEvent returned without flipping");
400 drm->current_front = drm->next_front;
401 drm->next_front = NULL;
408 pthread_mutex_lock(&drm->hdmi_mutex);
409 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo) {
411 int dst_x1 = 0, dst_y1 = 0;
413 if (drm->hdmi.bo->handle->width > bo->handle->width)
414 dst_x1 = (drm->hdmi.bo->handle->width - bo->handle->width) / 2;
415 if (drm->hdmi.bo->handle->height > bo->handle->height)
416 dst_y1 = (drm->hdmi.bo->handle->height - bo->handle->height) / 2;
418 drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
420 dst_x1 + bo->handle->width,
421 dst_y1 + bo->handle->height,
422 0, 0, bo->handle->width, bo->handle->height);
424 ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, drm->hdmi.bo->fb_id, 0, NULL);
425 if (ret && errno != EBUSY)
426 ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
427 strerror(errno), drm->hdmi.crtc_id, drm->hdmi.bo->fb_id);
429 pthread_mutex_unlock(&drm->hdmi_mutex);
431 /* set planes to be displayed */
432 gralloc_drm_set_planes(drm);
434 ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
435 DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
437 ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
438 strerror(errno), drm->primary.crtc_id, bo->fb_id);
439 /* try to set mode for next frame */
444 drm->next_front = bo;
450 * Wait for the next post.
452 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
454 unsigned int current, target;
458 if (drm->mode_quirk_vmwgfx)
463 memset(&vbl, 0, sizeof(vbl));
464 vbl.request.type = DRM_VBLANK_RELATIVE;
465 if (drm->vblank_secondary)
466 vbl.request.type |= DRM_VBLANK_SECONDARY;
467 vbl.request.sequence = 0;
469 /* get the current vblank */
470 ret = drmWaitVBlank(drm->fd, &vbl);
472 ALOGW("failed to get vblank");
476 current = vbl.reply.sequence;
480 target = drm->last_swap + drm->swap_interval - flip;
482 /* wait for vblank */
483 if (current < target || !flip) {
484 memset(&vbl, 0, sizeof(vbl));
485 vbl.request.type = DRM_VBLANK_ABSOLUTE;
486 if (drm->vblank_secondary)
487 vbl.request.type |= DRM_VBLANK_SECONDARY;
489 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
490 if (target < current)
494 vbl.request.sequence = target;
496 ret = drmWaitVBlank(drm->fd, &vbl);
498 ALOGW("failed to wait vblank");
503 drm->last_swap = vbl.reply.sequence + flip;
507 * Post a bo. This is not thread-safe.
509 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
511 struct gralloc_drm_t *drm = bo->drm;
514 if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
515 ALOGE("unable to post bo %p without fb", bo);
519 /* TODO spawn a thread to avoid waiting and race */
521 if (drm->first_post) {
522 if (drm->swap_mode == DRM_SWAP_COPY) {
523 struct gralloc_drm_bo_t *dst;
525 dst = (drm->next_front) ?
528 drm->drv->blit(drm->drv, dst, bo, 0, 0,
537 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
540 drm->current_front = bo;
541 if (drm->next_front == bo)
542 drm->next_front = NULL;
545 pthread_mutex_lock(&drm->hdmi_mutex);
546 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
547 drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
548 pthread_mutex_unlock(&drm->hdmi_mutex);
553 switch (drm->swap_mode) {
555 if (drm->swap_interval > 1)
556 drm_kms_wait_for_post(drm, 1);
557 ret = drm_kms_page_flip(drm, bo);
558 if (drm->next_front) {
560 * wait if the driver says so or the current front
561 * will be written by CPU
563 if (drm->mode_sync_flip ||
564 (drm->current_front->handle->usage &
565 GRALLOC_USAGE_SW_WRITE_MASK))
566 drm_kms_page_flip(drm, NULL);
570 drm_kms_wait_for_post(drm, 0);
571 drm->drv->blit(drm->drv, drm->current_front,
578 if (drm->mode_quirk_vmwgfx)
579 ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
582 case DRM_SWAP_SETCRTC:
583 drm_kms_wait_for_post(drm, 0);
584 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
586 pthread_mutex_lock(&drm->hdmi_mutex);
587 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
588 drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
589 pthread_mutex_unlock(&drm->hdmi_mutex);
591 drm->current_front = bo;
602 static struct gralloc_drm_t *drm_singleton;
604 static void on_signal(int sig)
606 struct gralloc_drm_t *drm = drm_singleton;
608 /* wait the pending flip */
609 if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
610 /* there is race, but this function is hacky enough to ignore that */
611 if (drm_singleton->waiting_flip)
612 usleep(100 * 1000); /* 100ms */
614 drm_kms_page_flip(drm_singleton, NULL);
620 static void drm_kms_init_features(struct gralloc_drm_t *drm)
622 const char *swap_mode;
624 /* call to the driver here, after KMS has been initialized */
625 drm->drv->init_kms_features(drm->drv, drm);
627 if (drm->swap_mode == DRM_SWAP_FLIP) {
628 struct sigaction act;
630 memset(&drm->evctx, 0, sizeof(drm->evctx));
631 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
632 drm->evctx.page_flip_handler = page_flip_handler;
635 * XXX GPU tends to freeze if the program is terminiated with a
636 * flip pending. What is the right way to handle the
639 sigemptyset(&act.sa_mask);
640 act.sa_handler = on_signal;
642 sigaction(SIGINT, &act, NULL);
643 sigaction(SIGTERM, &act, NULL);
647 else if (drm->swap_mode == DRM_SWAP_COPY) {
648 struct gralloc_drm_bo_t *front;
651 /* create the real front buffer */
652 front = gralloc_drm_bo_create(drm,
653 drm->primary.mode.hdisplay,
654 drm->primary.mode.vdisplay,
655 drm->primary.fb_format,
656 GRALLOC_USAGE_HW_FB);
657 if (front && gralloc_drm_bo_add_fb(front)) {
658 gralloc_drm_bo_decref(front);
662 /* abuse next_front */
664 drm->next_front = front;
666 drm->swap_mode = DRM_SWAP_SETCRTC;
669 switch (drm->swap_mode) {
676 case DRM_SWAP_SETCRTC:
677 swap_mode = "set-crtc";
684 ALOGD("will use %s for fb posting", swap_mode);
687 #define MARGIN_PERCENT 1.8 /* % of active vertical image*/
688 #define CELL_GRAN 8.0 /* assumed character cell granularity*/
689 #define MIN_PORCH 1 /* minimum front porch */
690 #define V_SYNC_RQD 3 /* width of vsync in lines */
691 #define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */
692 #define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
693 #define M 600.0 /* blanking formula gradient */
694 #define C 40.0 /* blanking formula offset */
695 #define K 128.0 /* blanking formula scaling factor */
696 #define J 20.0 /* blanking formula scaling factor */
697 /* C' and M' are part of the Blanking Duty Cycle computation */
698 #define C_PRIME (((C - J) * K / 256.0) + J)
699 #define M_PRIME (K / 256.0 * M)
701 static drmModeModeInfoPtr generate_mode(int h_pixels, int v_lines, float freq)
705 float v_field_rate_rqd;
713 float v_field_rate_est;
719 float total_active_pixels;
720 float ideal_duty_cycle;
728 float v_odd_front_porch_lines;
732 drmModeModeInfoPtr m = malloc(sizeof(drmModeModeInfo));
734 h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
735 v_lines_rnd = interlaced ? rint((float) v_lines) / 2.0 : rint((float) v_lines);
736 v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
737 top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
738 bottom_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
739 interlace = interlaced ? 0.5 : 0.0;
740 h_period_est = (((1.0 / v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP / 1000000.0)) / (v_lines_rnd + (2 * top_margin) + MIN_PORCH + interlace) * 1000000.0);
741 vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est);
742 v_back_porch = vsync_plus_bp - V_SYNC_RQD;
743 total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + interlace + MIN_PORCH;
744 v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
745 h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
746 v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
747 v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
748 left_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
749 right_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
750 total_active_pixels = h_pixels_rnd + left_margin + right_margin;
751 ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
752 h_blank = rint(total_active_pixels * ideal_duty_cycle / (100.0 - ideal_duty_cycle) / (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
753 total_pixels = total_active_pixels + h_blank;
754 pixel_freq = total_pixels / h_period;
755 h_freq = 1000.0 / h_period;
756 h_sync = rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
757 h_front_porch = (h_blank / 2.0) - h_sync;
758 v_odd_front_porch_lines = MIN_PORCH + interlace;
760 m->clock = ceil(pixel_freq) * 1000;
761 m->hdisplay = (int) (h_pixels_rnd);
762 m->hsync_start = (int) (h_pixels_rnd + h_front_porch);
763 m->hsync_end = (int) (h_pixels_rnd + h_front_porch + h_sync);
764 m->htotal = (int) (total_pixels);
766 m->vdisplay = (int) (v_lines_rnd);
767 m->vsync_start = (int) (v_lines_rnd + v_odd_front_porch_lines);
768 m->vsync_end = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
769 m->vtotal = (int) (total_v_lines);
778 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
780 char value[PROPERTY_VALUE_MAX];
781 drmModeModeInfoPtr mode;
783 int xres = 0, yres = 0, rate = 0;
786 if (property_get("debug.drm.mode", value, NULL)) {
787 char *p = value, *end;
789 /* parse <xres>x<yres>[@<bpp>] */
790 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
792 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
796 if ((xres && yres) || *bpp) {
797 ALOGI("will find the closest match for %dx%d@%d",
800 } else if (property_get("debug.drm.mode.force", value, NULL)) {
801 char *p = value, *end;
804 /* parse <xres>x<yres>[@<refreshrate>] */
805 if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
807 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
811 if (xres && yres && rate) {
812 ALOGI("will use %dx%d@%dHz", xres, yres, rate);
822 mode = generate_mode(xres, yres, rate);
825 for (i = 0; i < connector->count_modes; i++) {
826 drmModeModeInfoPtr m = &connector->modes[i];
830 tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
831 (m->vdisplay - yres) * (m->vdisplay - yres);
834 /* use the first preferred mode */
835 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
847 /* fallback to the first mode */
849 mode = &connector->modes[0];
851 ALOGI("Established mode:");
852 ALOGI("clock: %d, hdisplay: %d, hsync_start: %d, hsync_end: %d, htotal: %d, hskew: %d", mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->hskew);
853 ALOGI("vdisplay: %d, vsync_start: %d, vsync_end: %d, vtotal: %d, vscan: %d, vrefresh: %d", mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, mode->vscan, mode->vrefresh);
854 ALOGI("flags: %d, type: %d, name %s", mode->flags, mode->type, mode->name);
862 * Initialize KMS with a connector.
864 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
865 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
867 drmModeEncoderPtr encoder;
868 drmModeModeInfoPtr mode;
869 static int used_crtcs = 0;
872 if (!connector->count_modes)
875 encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
879 /* find first possible crtc which is not used yet */
880 for (i = 0; i < drm->resources->count_crtcs; i++) {
881 if (encoder->possible_crtcs & (1 << i) &&
882 (used_crtcs & (1 << i)) != (1 << i))
886 used_crtcs |= (1 << i);
888 drmModeFreeEncoder(encoder);
889 if (i == drm->resources->count_crtcs)
893 output->crtc_id = drm->resources->crtcs[i];
894 output->connector_id = connector->connector_id;
897 /* print connector info */
898 if (connector->count_modes > 1) {
899 ALOGI("there are %d modes on connector 0x%x, type %d",
900 connector->count_modes,
901 connector->connector_id,
902 connector->connector_type);
903 for (i = 0; i < connector->count_modes; i++)
904 ALOGI(" %s", connector->modes[i].name);
907 ALOGI("there is one mode on connector 0x%d: %s",
908 connector->connector_id,
909 connector->modes[0].name);
912 mode = find_mode(connector, &bpp);
914 ALOGI("the best mode is %s", mode->name);
916 output->mode = *mode;
919 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
923 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
927 if (connector->mmWidth && connector->mmHeight) {
928 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
929 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
936 #ifdef DRM_MODE_FEATURE_DIRTYFB
939 drm->clip.x2 = output->mode.hdisplay;
940 drm->clip.y2 = output->mode.vdisplay;
948 * Fetch a connector of particular type
950 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
958 for (i = 0; i < drm->resources->count_connectors; i++) {
959 drmModeConnectorPtr connector =
960 connector = drmModeGetConnector(drm->fd,
961 drm->resources->connectors[i]);
963 if (connector->connector_type == type &&
964 connector->connection == DRM_MODE_CONNECTED)
966 drmModeFreeConnector(connector);
974 * Initializes hdmi output with a connector and allocates
975 * a private framebuffer for it. This is called on startup if
976 * hdmi cable is connected and also on hotplug events.
978 static void init_hdmi_output(struct gralloc_drm_t *drm,
979 drmModeConnectorPtr connector)
981 drm_kms_init_with_connector(drm, &drm->hdmi, connector);
983 ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
984 __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
986 drm->hdmi.bo = gralloc_drm_bo_create(drm,
987 drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
989 GRALLOC_USAGE_HW_RENDER);
991 int err = gralloc_drm_bo_add_fb(drm->hdmi.bo);
993 ALOGE("%s: could not create drm fb, (%s)",
994 __func__, strerror(-err));
998 drm->hdmi_mode = HDMI_CLONED;
999 drm->hdmi.active = 1;
1004 * Thread that listens to uevents and checks if hdmi state changes
1006 static void *hdmi_observer(void *data)
1008 static char uevent_desc[4096];
1009 drmModeConnectorPtr hdmi;
1010 struct gralloc_drm_t *drm =
1011 (struct gralloc_drm_t *) data;
1015 memset(uevent_desc, 0, sizeof(uevent_desc));
1020 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
1022 if(len && strstr(uevent_desc, "devices/virtual/switch/hdmi")) {
1024 /* check what changed */
1025 const char *prop = uevent_desc + strlen(uevent_desc) + 1;
1029 const char *state = strstr(prop, "SWITCH_STATE=");
1031 unsigned int value = 0;
1032 state += strlen("SWITCH_STATE=");
1033 value = atoi(state);
1035 pthread_mutex_lock(&drm->hdmi_mutex);
1038 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1041 ALOGD("init hdmi on hotplug event");
1042 init_hdmi_output(drm, hdmi);
1044 /* will trigger modeset */
1045 drm->first_post = 1;
1047 drmModeFreeConnector(hdmi);
1049 pthread_mutex_unlock(&drm->hdmi_mutex);
1053 drm->hdmi.active = 0;
1055 ALOGD("destroy hdmi private buffer");
1056 gralloc_drm_bo_decref(drm->hdmi.bo);
1057 drm->hdmi.bo = NULL;
1059 pthread_mutex_unlock(&drm->hdmi_mutex);
1063 pthread_mutex_unlock(&drm->hdmi_mutex);
1066 /* next property/value pair */
1067 prop += strlen(prop) + 1;
1068 if (prop - uevent_desc >= len)
1082 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
1084 drmModeConnectorPtr lvds, hdmi;
1090 drm->resources = drmModeGetResources(drm->fd);
1091 if (!drm->resources) {
1092 ALOGE("failed to get modeset resources");
1096 drm->plane_resources = drmModeGetPlaneResources(drm->fd);
1097 if (!drm->plane_resources) {
1098 ALOGD("no planes found from drm resources");
1102 ALOGD("supported drm planes and formats");
1103 /* fill a helper structure for hwcomposer */
1104 drm->planes = calloc(drm->plane_resources->count_planes,
1105 sizeof(struct gralloc_drm_plane_t));
1107 for (i = 0; i < drm->plane_resources->count_planes; i++) {
1108 drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
1109 drm->plane_resources->planes[i]);
1111 ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
1112 for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
1113 ALOGD(" format %c%c%c%c",
1114 (drm->planes[i].drm_plane->formats[j]),
1115 (drm->planes[i].drm_plane->formats[j])>>8,
1116 (drm->planes[i].drm_plane->formats[j])>>16,
1117 (drm->planes[i].drm_plane->formats[j])>>24);
1121 /* find the crtc/connector/mode to use */
1122 lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
1124 drm_kms_init_with_connector(drm, &drm->primary, lvds);
1125 drmModeFreeConnector(lvds);
1126 drm->primary.active = 1;
1129 /* if still no connector, find first connected connector and try it */
1130 if (!drm->primary.active) {
1132 for (i = 0; i < drm->resources->count_connectors; i++) {
1133 drmModeConnectorPtr connector;
1135 connector = drmModeGetConnector(drm->fd,
1136 drm->resources->connectors[i]);
1138 if (connector->connection == DRM_MODE_CONNECTED) {
1139 if (!drm_kms_init_with_connector(drm,
1140 &drm->primary, connector))
1144 drmModeFreeConnector(connector);
1147 if (i == drm->resources->count_connectors) {
1148 ALOGE("failed to find a valid crtc/connector/mode combination");
1149 drmModeFreeResources(drm->resources);
1150 drm->resources = NULL;
1157 /* check if hdmi is connected already */
1158 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1161 if (hdmi->connector_id == drm->primary.connector_id) {
1162 /* special case: our primary connector is hdmi */
1163 ALOGD("hdmi is the primary connector");
1164 goto skip_hdmi_modes;
1167 ALOGD("init hdmi on startup");
1168 init_hdmi_output(drm, hdmi);
1170 drmModeFreeConnector(hdmi);
1173 goto skip_hdmi_modes;
1174 /* launch hdmi observer thread */
1175 pthread_mutex_init(&drm->hdmi_mutex, NULL);
1176 pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
1180 drm_kms_init_features(drm);
1181 drm->first_post = 1;
1186 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1188 switch (drm->swap_mode) {
1190 drm_kms_page_flip(drm, NULL);
1194 struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1195 &drm->current_front : &drm->next_front;
1198 gralloc_drm_bo_decref(*bo);
1208 if (drm->resources) {
1209 drmModeFreeResources(drm->resources);
1210 drm->resources = NULL;
1215 for (i = 0; i < drm->plane_resources->count_planes; i++)
1216 drmModeFreePlane(drm->planes[i].drm_plane);
1221 if (drm->plane_resources) {
1222 drmModeFreePlaneResources(drm->plane_resources);
1223 drm->plane_resources = NULL;
1226 /* destroy private buffer of hdmi output */
1228 gralloc_drm_bo_decref(drm->hdmi.bo);
1230 drm_singleton = NULL;
1233 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1235 return (drm->resources != NULL);
1239 * Initialize a framebuffer device with KMS info.
1241 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1242 struct framebuffer_device_t *fb)
1244 *((uint32_t *) &fb->flags) = 0x0;
1245 *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
1246 *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
1247 *((int *) &fb->stride) = drm->primary.mode.hdisplay;
1248 *((float *) &fb->fps) = drm->primary.mode.vrefresh;
1250 *((int *) &fb->format) = drm->primary.fb_format;
1251 *((float *) &fb->xdpi) = drm->primary.xdpi;
1252 *((float *) &fb->ydpi) = drm->primary.ydpi;
1253 *((int *) &fb->minSwapInterval) = drm->swap_interval;
1254 *((int *) &fb->maxSwapInterval) = drm->swap_interval;
1258 * Return true if fb posting is pipelined.
1260 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1262 return (drm->swap_mode != DRM_SWAP_SETCRTC);