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>
44 const char *subsystem;
45 const char *device_name;
52 static void parse_event(const char *msg, struct uevent *uevent)
56 uevent->subsystem = "";
59 uevent->device_name = "";
61 uevent->switchstate = -1;
64 if (!strncmp(msg, "ACTION=", 7)) {
67 } else if (!strncmp(msg, "DEVPATH=", 8)) {
70 } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
72 uevent->subsystem = msg;
73 } else if (!strncmp(msg, "MAJOR=", 6)) {
75 uevent->major = atoi(msg);
76 } else if (!strncmp(msg, "MINOR=", 6)) {
78 uevent->minor = atoi(msg);
79 } else if (!strncmp(msg, "DEVNAME=", 8)) {
81 uevent->device_name = msg;
82 } else if (!strncmp(msg, "HOTPLUG=1", 9)) {
85 } else if (!strncmp(msg, "SWITCH_STATE=", 13)) {
87 uevent->switchstate = atoi(msg);
90 /* advance to after the next \0 */
97 * Return true if a bo needs fb.
99 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
101 return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
102 bo->drm->swap_mode != DRM_SWAP_COPY);
105 static unsigned int drm_format_from_hal(int hal_format)
108 case HAL_PIXEL_FORMAT_RGB_888:
109 case HAL_PIXEL_FORMAT_BGRA_8888:
110 return DRM_FORMAT_XRGB8888;
111 case HAL_PIXEL_FORMAT_RGBX_8888:
112 return DRM_FORMAT_XBGR8888;
113 case HAL_PIXEL_FORMAT_RGBA_8888:
114 return DRM_FORMAT_RGBA8888;
115 case HAL_PIXEL_FORMAT_RGB_565:
116 return DRM_FORMAT_RGB565;
117 case HAL_PIXEL_FORMAT_YV12:
118 return DRM_FORMAT_YUV420;
119 case HAL_PIXEL_FORMAT_DRM_NV12:
120 return DRM_FORMAT_NV12;
127 * Modify pitches, offsets and handles according to
128 * the format and return corresponding drm format value
130 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
131 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
133 struct gralloc_drm_t *drm = bo->drm;
135 pitches[0] = bo->handle->stride;
136 handles[0] = bo->fb_handle;
138 /* driver takes care of HW specific padding, alignment etc. */
139 if (drm->drv->resolve_format)
140 drm->drv->resolve_format(drm->drv, bo,
141 pitches, offsets, handles);
143 return drm_format_from_hal(bo->handle->format);
147 * Returns planes that are supported for a particular format
149 unsigned int planes_for_format(struct gralloc_drm_t *drm,
152 unsigned int i, j, mask = 0;
153 unsigned int drm_format = drm_format_from_hal(hal_format);
154 struct gralloc_drm_plane_t *plane = drm->planes;
156 /* no planes available */
160 /* iterate through planes, mark those that match format */
161 for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
162 for (j=0; j<plane->drm_plane->count_formats; j++)
163 if (plane->drm_plane->formats[j] == drm_format)
164 mask |= (1U << plane->drm_plane->plane_id);
170 * Add a fb object for a bo.
172 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
174 uint32_t pitches[4] = { 0, 0, 0, 0 };
175 uint32_t offsets[4] = { 0, 0, 0, 0 };
176 uint32_t handles[4] = { 0, 0, 0, 0 };
181 int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
183 if (drm_format == 0) {
184 ALOGE("error resolving drm format");
188 return drmModeAddFB2(bo->drm->fd,
189 bo->handle->width, bo->handle->height,
190 drm_format, handles, pitches, offsets,
191 (uint32_t *) &bo->fb_id, 0);
195 * Remove a fb object for a bo.
197 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
200 drmModeRmFB(bo->drm->fd, bo->fb_id);
208 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
209 struct gralloc_drm_output *output, int fb_id)
213 ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
214 0, 0, &output->connector_id, 1, &output->mode);
216 ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
217 strerror(errno), output->crtc_id, fb_id, output->connector_id,
218 output->mode.hdisplay, output->mode.vdisplay);
222 if (drm->mode_quirk_vmwgfx)
223 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
229 * Callback for a page flip event.
231 static void page_flip_handler(int fd, unsigned int sequence,
232 unsigned int tv_sec, unsigned int tv_usec,
235 struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
237 /* ack the last scheduled flip */
238 drm->current_front = drm->next_front;
239 drm->next_front = NULL;
245 static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
246 struct gralloc_drm_plane_t *plane)
248 struct gralloc_drm_bo_t *bo = NULL;
252 bo = gralloc_drm_bo_from_handle(plane->handle);
254 // create a framebuffer if does not exist
255 if (bo && bo->fb_id == 0) {
256 err = gralloc_drm_bo_add_fb(bo);
258 ALOGE("%s: could not create drm fb, (%s)",
259 __func__, strerror(-err));
264 err = drmModeSetPlane(drm->fd,
265 plane->drm_plane->plane_id,
266 drm->primary.crtc_id,
279 /* clear plane_mask so that this buffer won't be tried again */
280 struct gralloc_drm_handle_t *drm_handle =
281 (struct gralloc_drm_handle_t *) plane->handle;
282 drm_handle->plane_mask = 0;
284 ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
286 plane->drm_plane->plane_id,
287 drm->primary.crtc_id,
292 gralloc_drm_bo_decref(plane->prev);
303 * Returns if a particular plane is supported with the implementation
305 static unsigned is_plane_supported(const struct gralloc_drm_t *drm,
306 const struct gralloc_drm_plane_t *plane)
308 /* Planes are only supported on primary pipe for now */
309 return plane->drm_plane->possible_crtcs & (1 << drm->primary.pipe);
313 * Sets all the active planes to be displayed.
315 static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
317 struct gralloc_drm_plane_t *plane = drm->planes;
319 for (i = 0; i < drm->plane_resources->count_planes;
321 /* plane is not in use at all */
322 if (!plane->active && !plane->handle)
325 /* plane is active, safety check if it is supported */
326 if (!is_plane_supported(drm, plane))
327 ALOGE("%s: plane %d is not supported",
328 __func__, plane->drm_plane->plane_id);
331 * Disable overlay if it is not active
332 * or if there is error during setplane
337 if (gralloc_drm_bo_setplane(drm, plane))
343 * Interface for HWC, used to reserve a plane for a layer.
345 int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
346 buffer_handle_t handle,
358 struct gralloc_drm_handle_t *drm_handle =
359 gralloc_drm_handle(handle);
360 int plane_count = drm->plane_resources->count_planes;
361 struct gralloc_drm_plane_t *plane = drm->planes;
363 /* no supported planes for this handle */
364 if (!drm_handle->plane_mask) {
365 ALOGE("%s: buffer %p cannot be shown on a plane\n",
366 __func__, drm_handle);
370 for (j = 0; j < plane_count; j++, plane++) {
373 * handle may be suitable to be shown on a plane, in
374 * addition we need to check that this particular plane
375 * is supported by the current implementation
377 if (!is_plane_supported(drm, plane))
380 /* if plane is available and can support this buffer */
381 if (!plane->active &&
382 drm_handle->plane_mask &
383 (1U << plane->drm_plane->plane_id)) {
385 plane->dst_x = dst_x;
386 plane->dst_y = dst_y;
387 plane->dst_w = dst_w;
388 plane->dst_h = dst_h;
389 plane->src_x = src_x;
390 plane->src_y = src_y;
391 plane->src_w = src_w;
392 plane->src_h = src_h;
393 plane->handle = handle;
401 /* no free planes available */
406 * Interface for HWC, used to disable all the overlays. Plane id
407 * is also set to 0 as it should be mappable to a particular layer only
408 * if it has been reserved with 'reserve_plane'.
410 void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
412 struct gralloc_drm_plane_t *plane = drm->planes;
415 for (i = 0; i < drm->plane_resources->count_planes; i++, plane++) {
422 * Interface for HWC, used to change handle of a reserved plane.
424 int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
425 uint32_t id, buffer_handle_t handle)
427 struct gralloc_drm_plane_t *plane = drm->planes;
430 for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
431 if (plane->active && plane->id == id) {
432 plane->handle = handle;
439 static int drm_kms_blit_to_hdmi(struct gralloc_drm_t *drm, struct gralloc_drm_bo_t *bo)
442 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo) {
444 int dst_x1 = 0, dst_y1 = 0;
446 if (drm->hdmi.bo->handle->width > bo->handle->width)
447 dst_x1 = (drm->hdmi.bo->handle->width - bo->handle->width) / 2;
448 if (drm->hdmi.bo->handle->height > bo->handle->height)
449 dst_y1 = (drm->hdmi.bo->handle->height - bo->handle->height) / 2;
451 drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
453 dst_x1 + bo->handle->width,
454 dst_y1 + bo->handle->height,
455 0, 0, bo->handle->width, bo->handle->height);
457 ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, drm->hdmi.bo->fb_id, 0, NULL);
458 if (ret && errno != EBUSY)
459 ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
460 strerror(errno), drm->hdmi.crtc_id, drm->hdmi.bo->fb_id);
467 * Schedule a page flip.
469 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
470 struct gralloc_drm_bo_t *bo)
474 /* there is another flip pending */
475 while (drm->next_front) {
476 drm->waiting_flip = 1;
477 drmHandleEvent(drm->fd, &drm->evctx);
478 drm->waiting_flip = 0;
479 if (drm->next_front) {
480 /* record an error and break */
481 ALOGE("drmHandleEvent returned without flipping");
482 drm->current_front = drm->next_front;
483 drm->next_front = NULL;
490 pthread_mutex_lock(&drm->hdmi_mutex);
491 drm_kms_blit_to_hdmi(drm, bo);
492 pthread_mutex_unlock(&drm->hdmi_mutex);
494 /* set planes to be displayed */
495 gralloc_drm_set_planes(drm);
497 ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
498 DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
500 ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
501 strerror(errno), drm->primary.crtc_id, bo->fb_id);
502 /* try to set mode for next frame */
507 drm->next_front = bo;
513 * Wait for the next post.
515 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
517 unsigned int current, target;
521 if (drm->mode_quirk_vmwgfx)
526 memset(&vbl, 0, sizeof(vbl));
527 vbl.request.type = DRM_VBLANK_RELATIVE;
528 if (drm->vblank_secondary)
529 vbl.request.type |= DRM_VBLANK_SECONDARY;
530 vbl.request.sequence = 0;
532 /* get the current vblank */
533 ret = drmWaitVBlank(drm->fd, &vbl);
535 ALOGW("failed to get vblank");
539 current = vbl.reply.sequence;
543 target = drm->last_swap + drm->swap_interval - flip;
545 /* wait for vblank */
546 if (current < target || !flip) {
547 memset(&vbl, 0, sizeof(vbl));
548 vbl.request.type = DRM_VBLANK_ABSOLUTE;
549 if (drm->vblank_secondary)
550 vbl.request.type |= DRM_VBLANK_SECONDARY;
552 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
553 if (target < current)
557 vbl.request.sequence = target;
559 ret = drmWaitVBlank(drm->fd, &vbl);
561 ALOGW("failed to wait vblank");
566 drm->last_swap = vbl.reply.sequence + flip;
570 * Post a bo. This is not thread-safe.
572 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
574 struct gralloc_drm_t *drm = bo->drm;
577 if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
578 ALOGE("unable to post bo %p without fb", bo);
582 /* TODO spawn a thread to avoid waiting and race */
584 if (drm->first_post) {
585 if (drm->swap_mode == DRM_SWAP_COPY) {
586 struct gralloc_drm_bo_t *dst;
588 dst = (drm->next_front) ?
591 drm->drv->blit(drm->drv, dst, bo, 0, 0,
600 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
603 drm->current_front = bo;
604 if (drm->next_front == bo)
605 drm->next_front = NULL;
608 pthread_mutex_lock(&drm->hdmi_mutex);
609 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
610 drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
611 pthread_mutex_unlock(&drm->hdmi_mutex);
616 switch (drm->swap_mode) {
618 if (drm->swap_interval > 1)
619 drm_kms_wait_for_post(drm, 1);
620 ret = drm_kms_page_flip(drm, bo);
621 if (drm->next_front) {
623 * wait if the driver says so or the current front
624 * will be written by CPU
626 if (drm->mode_sync_flip ||
627 (drm->current_front->handle->usage &
628 GRALLOC_USAGE_SW_WRITE_MASK))
629 drm_kms_page_flip(drm, NULL);
633 drm_kms_wait_for_post(drm, 0);
634 drm->drv->blit(drm->drv, drm->current_front,
641 if (drm->mode_quirk_vmwgfx)
642 ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
645 case DRM_SWAP_SETCRTC:
646 drm_kms_wait_for_post(drm, 0);
647 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
649 pthread_mutex_lock(&drm->hdmi_mutex);
650 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
651 drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
652 pthread_mutex_unlock(&drm->hdmi_mutex);
654 drm->current_front = bo;
665 static struct gralloc_drm_t *drm_singleton;
667 static void on_signal(int sig)
669 struct gralloc_drm_t *drm = drm_singleton;
671 /* wait the pending flip */
672 if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
673 /* there is race, but this function is hacky enough to ignore that */
674 if (drm_singleton->waiting_flip)
675 usleep(100 * 1000); /* 100ms */
677 drm_kms_page_flip(drm_singleton, NULL);
683 static void drm_kms_init_features(struct gralloc_drm_t *drm)
685 const char *swap_mode;
687 /* call to the driver here, after KMS has been initialized */
688 drm->drv->init_kms_features(drm->drv, drm);
690 if (drm->swap_mode == DRM_SWAP_FLIP) {
691 struct sigaction act;
693 memset(&drm->evctx, 0, sizeof(drm->evctx));
694 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
695 drm->evctx.page_flip_handler = page_flip_handler;
698 * XXX GPU tends to freeze if the program is terminiated with a
699 * flip pending. What is the right way to handle the
702 sigemptyset(&act.sa_mask);
703 act.sa_handler = on_signal;
705 sigaction(SIGINT, &act, NULL);
706 sigaction(SIGTERM, &act, NULL);
710 else if (drm->swap_mode == DRM_SWAP_COPY) {
711 struct gralloc_drm_bo_t *front;
714 /* create the real front buffer */
715 front = gralloc_drm_bo_create(drm,
716 drm->primary.mode.hdisplay,
717 drm->primary.mode.vdisplay,
718 drm->primary.fb_format,
719 GRALLOC_USAGE_HW_FB);
720 if (front && gralloc_drm_bo_add_fb(front)) {
721 gralloc_drm_bo_decref(front);
725 /* abuse next_front */
727 drm->next_front = front;
729 drm->swap_mode = DRM_SWAP_SETCRTC;
732 switch (drm->swap_mode) {
739 case DRM_SWAP_SETCRTC:
740 swap_mode = "set-crtc";
747 ALOGD("will use %s for fb posting", swap_mode);
750 #define MARGIN_PERCENT 1.8 /* % of active vertical image*/
751 #define CELL_GRAN 8.0 /* assumed character cell granularity*/
752 #define MIN_PORCH 1 /* minimum front porch */
753 #define V_SYNC_RQD 3 /* width of vsync in lines */
754 #define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */
755 #define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
756 #define M 600.0 /* blanking formula gradient */
757 #define C 40.0 /* blanking formula offset */
758 #define K 128.0 /* blanking formula scaling factor */
759 #define J 20.0 /* blanking formula scaling factor */
760 /* C' and M' are part of the Blanking Duty Cycle computation */
761 #define C_PRIME (((C - J) * K / 256.0) + J)
762 #define M_PRIME (K / 256.0 * M)
764 static drmModeModeInfoPtr generate_mode(int h_pixels, int v_lines, float freq)
768 float v_field_rate_rqd;
776 float v_field_rate_est;
782 float total_active_pixels;
783 float ideal_duty_cycle;
791 float v_odd_front_porch_lines;
795 drmModeModeInfoPtr m = malloc(sizeof(drmModeModeInfo));
797 h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
798 v_lines_rnd = interlaced ? rint((float) v_lines) / 2.0 : rint((float) v_lines);
799 v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
800 top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
801 bottom_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
802 interlace = interlaced ? 0.5 : 0.0;
803 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);
804 vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est);
805 v_back_porch = vsync_plus_bp - V_SYNC_RQD;
806 total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + interlace + MIN_PORCH;
807 v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
808 h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
809 v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
810 v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
811 left_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
812 right_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
813 total_active_pixels = h_pixels_rnd + left_margin + right_margin;
814 ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
815 h_blank = rint(total_active_pixels * ideal_duty_cycle / (100.0 - ideal_duty_cycle) / (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
816 total_pixels = total_active_pixels + h_blank;
817 pixel_freq = total_pixels / h_period;
818 h_freq = 1000.0 / h_period;
819 h_sync = rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
820 h_front_porch = (h_blank / 2.0) - h_sync;
821 v_odd_front_porch_lines = MIN_PORCH + interlace;
823 m->clock = ceil(pixel_freq) * 1000;
824 m->hdisplay = (int) (h_pixels_rnd);
825 m->hsync_start = (int) (h_pixels_rnd + h_front_porch);
826 m->hsync_end = (int) (h_pixels_rnd + h_front_porch + h_sync);
827 m->htotal = (int) (total_pixels);
829 m->vdisplay = (int) (v_lines_rnd);
830 m->vsync_start = (int) (v_lines_rnd + v_odd_front_porch_lines);
831 m->vsync_end = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
832 m->vtotal = (int) (total_v_lines);
841 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
843 char value[PROPERTY_VALUE_MAX];
844 drmModeModeInfoPtr mode;
846 int xres = 0, yres = 0, rate = 0;
849 if (property_get("debug.drm.mode", value, NULL)) {
850 char *p = value, *end;
852 /* parse <xres>x<yres>[@<bpp>] */
853 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
855 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
859 if ((xres && yres) || *bpp) {
860 ALOGI("will find the closest match for %dx%d@%d",
863 } else if (property_get("debug.drm.mode.force", value, NULL)) {
864 char *p = value, *end;
867 /* parse <xres>x<yres>[@<refreshrate>] */
868 if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
870 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
874 if (xres && yres && rate) {
875 ALOGI("will use %dx%d@%dHz", xres, yres, rate);
885 mode = generate_mode(xres, yres, rate);
888 for (i = 0; i < connector->count_modes; i++) {
889 drmModeModeInfoPtr m = &connector->modes[i];
893 tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
894 (m->vdisplay - yres) * (m->vdisplay - yres);
897 /* use the first preferred mode */
898 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
910 /* fallback to the first mode */
912 mode = &connector->modes[0];
914 ALOGI("Established mode:");
915 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);
916 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);
917 ALOGI("flags: %d, type: %d, name %s", mode->flags, mode->type, mode->name);
925 * Initialize KMS with a connector.
927 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
928 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
930 drmModeEncoderPtr encoder;
931 drmModeModeInfoPtr mode;
932 static int used_crtcs = 0;
935 if (!connector->count_modes)
938 encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
942 /* find first possible crtc which is not used yet */
943 for (i = 0; i < drm->resources->count_crtcs; i++) {
944 if (encoder->possible_crtcs & (1 << i) &&
945 (used_crtcs & (1 << i)) != (1 << i))
949 used_crtcs |= (1 << i);
951 drmModeFreeEncoder(encoder);
952 if (i == drm->resources->count_crtcs)
956 output->crtc_id = drm->resources->crtcs[i];
957 output->connector_id = connector->connector_id;
960 /* print connector info */
961 if (connector->count_modes > 1) {
962 ALOGI("there are %d modes on connector 0x%x, type %d",
963 connector->count_modes,
964 connector->connector_id,
965 connector->connector_type);
966 for (i = 0; i < connector->count_modes; i++)
967 ALOGI(" %s", connector->modes[i].name);
970 ALOGI("there is one mode on connector 0x%d: %s",
971 connector->connector_id,
972 connector->modes[0].name);
975 mode = find_mode(connector, &bpp);
977 ALOGI("the best mode is %s", mode->name);
979 output->mode = *mode;
982 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
986 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
990 if (connector->mmWidth && connector->mmHeight) {
991 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
992 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
999 #ifdef DRM_MODE_FEATURE_DIRTYFB
1002 drm->clip.x2 = output->mode.hdisplay;
1003 drm->clip.y2 = output->mode.vdisplay;
1011 * Fetch a connector of particular type
1013 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
1018 if (!drm->resources)
1021 for (i = 0; i < drm->resources->count_connectors; i++) {
1022 drmModeConnectorPtr connector =
1023 connector = drmModeGetConnector(drm->fd,
1024 drm->resources->connectors[i]);
1026 if (connector->connector_type == type &&
1027 connector->connection == DRM_MODE_CONNECTED)
1029 drmModeFreeConnector(connector);
1037 * Initializes hdmi output with a connector and allocates
1038 * a private framebuffer for it. This is called on startup if
1039 * hdmi cable is connected and also on hotplug events.
1041 static int init_hdmi_output(struct gralloc_drm_t *drm,
1042 drmModeConnectorPtr connector)
1044 drm_kms_init_with_connector(drm, &drm->hdmi, connector);
1046 ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
1047 __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
1049 drm->hdmi.bo = gralloc_drm_bo_create(drm,
1050 drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
1051 drm->hdmi.fb_format,
1052 GRALLOC_USAGE_HW_RENDER);
1054 int err = gralloc_drm_bo_add_fb(drm->hdmi.bo);
1056 ALOGE("%s: could not create drm fb, (%s)",
1057 __func__, strerror(-err));
1061 drm->hdmi_mode = HDMI_CLONED;
1062 drm->hdmi.active = 1;
1069 * Thread that listens to uevents and checks if hdmi state changes
1071 static void *hdmi_observer(void *data)
1073 static char uevent_desc[4096];
1074 drmModeConnectorPtr hdmi;
1075 struct gralloc_drm_t *drm =
1076 (struct gralloc_drm_t *) data;
1077 struct uevent event;
1081 memset(uevent_desc, 0, sizeof(uevent_desc));
1086 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
1089 parse_event(uevent_desc, &event);
1090 ALOGD_IF(0, "event { '%s', '%s', '%s', %d, %d, %d, %d }\n",
1091 event.action, event.path, event.subsystem,
1092 event.major, event.minor,
1093 event.switchstate, event.hotplug);
1095 if (!strcmp(event.path, "devices/virtual/switch/hdmi")) {
1096 if (event.switchstate != -1) {
1097 pthread_mutex_lock(&drm->hdmi_mutex);
1099 if (event.switchstate) {
1100 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1102 ALOGD("init hdmi on switch_state event");
1103 init_hdmi_output(drm, hdmi);
1105 /* will trigger modeset */
1106 drm->first_post = 1;
1108 drmModeFreeConnector(hdmi);
1111 drm->hdmi.active = 0;
1113 ALOGD("destroy hdmi private buffer");
1114 gralloc_drm_bo_decref(drm->hdmi.bo);
1115 drm->hdmi.bo = NULL;
1118 pthread_mutex_unlock(&drm->hdmi_mutex);
1120 } else if (!strcmp(event.subsystem, "drm") &&
1121 !strcmp(event.device_name, "dri/card0") && event.hotplug) {
1122 pthread_mutex_lock(&drm->hdmi_mutex);
1124 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1125 if (hdmi && !drm->hdmi.active) {
1126 ALOGD("init hdmi on hotplug event");
1127 if (!init_hdmi_output(drm, hdmi)) {
1128 drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
1131 /* will trigger modeset */
1132 drm->first_post = 1;
1133 } else if (!hdmi && drm->hdmi.active) {
1134 drm->hdmi.active = 0;
1136 ALOGD("destroy hdmi private buffer");
1137 gralloc_drm_bo_decref(drm->hdmi.bo);
1138 drm->hdmi.bo = NULL;
1142 drmModeFreeConnector(hdmi);
1144 pthread_mutex_unlock(&drm->hdmi_mutex);
1156 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
1158 drmModeConnectorPtr lvds, hdmi;
1164 drm->resources = drmModeGetResources(drm->fd);
1165 if (!drm->resources) {
1166 ALOGE("failed to get modeset resources");
1170 drm->plane_resources = drmModeGetPlaneResources(drm->fd);
1171 if (!drm->plane_resources) {
1172 ALOGD("no planes found from drm resources");
1176 ALOGD("supported drm planes and formats");
1177 /* fill a helper structure for hwcomposer */
1178 drm->planes = calloc(drm->plane_resources->count_planes,
1179 sizeof(struct gralloc_drm_plane_t));
1181 for (i = 0; i < drm->plane_resources->count_planes; i++) {
1182 drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
1183 drm->plane_resources->planes[i]);
1185 ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
1186 for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
1187 ALOGD(" format %c%c%c%c",
1188 (drm->planes[i].drm_plane->formats[j]),
1189 (drm->planes[i].drm_plane->formats[j])>>8,
1190 (drm->planes[i].drm_plane->formats[j])>>16,
1191 (drm->planes[i].drm_plane->formats[j])>>24);
1195 /* find the crtc/connector/mode to use */
1196 lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
1198 drm_kms_init_with_connector(drm, &drm->primary, lvds);
1199 drmModeFreeConnector(lvds);
1200 drm->primary.active = 1;
1203 /* if still no connector, find first connected connector and try it */
1204 if (!drm->primary.active) {
1206 for (i = 0; i < drm->resources->count_connectors; i++) {
1207 drmModeConnectorPtr connector;
1209 connector = drmModeGetConnector(drm->fd,
1210 drm->resources->connectors[i]);
1212 if (connector->connection == DRM_MODE_CONNECTED) {
1213 if (!drm_kms_init_with_connector(drm,
1214 &drm->primary, connector))
1218 drmModeFreeConnector(connector);
1221 if (i == drm->resources->count_connectors) {
1222 ALOGE("failed to find a valid crtc/connector/mode combination");
1223 drmModeFreeResources(drm->resources);
1224 drm->resources = NULL;
1231 /* check if hdmi is connected already */
1232 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1235 if (hdmi->connector_id == drm->primary.connector_id) {
1236 /* special case: our primary connector is hdmi */
1237 ALOGD("hdmi is the primary connector");
1238 goto skip_hdmi_modes;
1241 ALOGD("init hdmi on startup");
1242 init_hdmi_output(drm, hdmi);
1244 drmModeFreeConnector(hdmi);
1247 /* launch hdmi observer thread */
1248 pthread_mutex_init(&drm->hdmi_mutex, NULL);
1249 pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
1253 drm_kms_init_features(drm);
1254 drm->first_post = 1;
1259 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1261 switch (drm->swap_mode) {
1263 drm_kms_page_flip(drm, NULL);
1267 struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1268 &drm->current_front : &drm->next_front;
1271 gralloc_drm_bo_decref(*bo);
1281 if (drm->resources) {
1282 drmModeFreeResources(drm->resources);
1283 drm->resources = NULL;
1288 for (i = 0; i < drm->plane_resources->count_planes; i++)
1289 drmModeFreePlane(drm->planes[i].drm_plane);
1294 if (drm->plane_resources) {
1295 drmModeFreePlaneResources(drm->plane_resources);
1296 drm->plane_resources = NULL;
1299 /* destroy private buffer of hdmi output */
1301 gralloc_drm_bo_decref(drm->hdmi.bo);
1303 drm_singleton = NULL;
1306 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1308 return (drm->resources != NULL);
1312 * Initialize a framebuffer device with KMS info.
1314 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1315 struct framebuffer_device_t *fb)
1317 *((uint32_t *) &fb->flags) = 0x0;
1318 *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
1319 *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
1320 *((int *) &fb->stride) = drm->primary.mode.hdisplay;
1321 *((float *) &fb->fps) = drm->primary.mode.vrefresh;
1323 *((int *) &fb->format) = drm->primary.fb_format;
1324 *((float *) &fb->xdpi) = drm->primary.xdpi;
1325 *((float *) &fb->ydpi) = drm->primary.ydpi;
1326 *((int *) &fb->minSwapInterval) = drm->swap_interval;
1327 *((int *) &fb->maxSwapInterval) = drm->swap_interval;
1331 * Return true if fb posting is pipelined.
1333 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1335 return (drm->swap_mode != DRM_SWAP_SETCRTC);