2 * Copyright © 2007 Red Hat, Inc.
3 * Copyright © 2008 Maarten Maathuis
4 * Copyright © 2011 Texas Instruments, Inc
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Dave Airlie <airlied@redhat.com>
28 * Ian Elliott <ianelliottus@yahoo.com>
35 /* TODO cleanup #includes, remove unnecessary ones */
37 #include "xorgVersion.h"
47 /* All drivers should typically include these */
49 #include "xf86_OSproc.h"
50 #define PPC_MMIO_IS_BE
52 #include "mipointer.h"
54 /* All drivers implementing backing store need this */
62 #include "xf86RandR12.h"
63 #include "dixstruct.h"
64 #include "scrnintstr.h"
70 #include <X11/extensions/Xv.h>
72 #include "xf86Cursor.h"
77 #include <X11/extensions/randr.h>
79 #ifdef HAVE_XEXTPROTO_71
80 #include <X11/extensions/dpmsconst.h>
83 #include <X11/extensions/dpms.h>
86 #include "omap_driver.h"
90 #include "xf86drmMode.h"
91 #include "drm_fourcc.h"
92 #include "X11/Xatom.h"
94 #include <sys/ioctl.h>
98 /* hardware cursor: */
104 } drmmode_cursor_rec, *drmmode_cursor_ptr;
109 drmModeResPtr mode_res;
111 struct udev_monitor *uevent_monitor;
112 InputHandlerProc uevent_handler;
113 drmmode_cursor_ptr cursor;
114 } drmmode_rec, *drmmode_ptr;
118 drmModeCrtcPtr mode_crtc;
119 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
122 drmModePropertyPtr mode_prop;
123 int index; /* Index within the kernel-side property arrays for
125 int num_atoms; /* if range prop, num_atoms == 1; if enum prop,
126 * num_atoms == num_enums + 1 */
128 } drmmode_prop_rec, *drmmode_prop_ptr;
133 drmModeConnectorPtr mode_output;
134 drmModeEncoderPtr mode_encoder;
135 drmModePropertyBlobPtr edid_blob;
137 drmmode_prop_ptr props;
138 } drmmode_output_private_rec, *drmmode_output_private_ptr;
140 static void drmmode_output_dpms(xf86OutputPtr output, int mode);
141 void drmmode_remove_fb(ScrnInfoPtr pScrn);
144 drmmode_from_scrn(ScrnInfoPtr pScrn)
146 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
147 drmmode_crtc_private_ptr drmmode_crtc;
149 drmmode_crtc = xf86_config->crtc[0]->driver_private;
150 return drmmode_crtc->drmmode;
154 drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
157 memset(mode, 0, sizeof(DisplayModeRec));
158 mode->status = MODE_OK;
160 mode->Clock = kmode->clock;
162 mode->HDisplay = kmode->hdisplay;
163 mode->HSyncStart = kmode->hsync_start;
164 mode->HSyncEnd = kmode->hsync_end;
165 mode->HTotal = kmode->htotal;
166 mode->HSkew = kmode->hskew;
168 mode->VDisplay = kmode->vdisplay;
169 mode->VSyncStart = kmode->vsync_start;
170 mode->VSyncEnd = kmode->vsync_end;
171 mode->VTotal = kmode->vtotal;
172 mode->VScan = kmode->vscan;
174 mode->Flags = kmode->flags; //& FLAG_BITS;
175 mode->name = strdup(kmode->name);
177 DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode);
179 if (kmode->type & DRM_MODE_TYPE_DRIVER)
180 mode->type = M_T_DRIVER;
181 if (kmode->type & DRM_MODE_TYPE_PREFERRED)
182 mode->type |= M_T_PREFERRED;
184 xf86SetModeCrtc (mode, pScrn->adjustFlags);
188 drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
191 memset(kmode, 0, sizeof(*kmode));
193 kmode->clock = mode->Clock;
194 kmode->hdisplay = mode->HDisplay;
195 kmode->hsync_start = mode->HSyncStart;
196 kmode->hsync_end = mode->HSyncEnd;
197 kmode->htotal = mode->HTotal;
198 kmode->hskew = mode->HSkew;
200 kmode->vdisplay = mode->VDisplay;
201 kmode->vsync_start = mode->VSyncStart;
202 kmode->vsync_end = mode->VSyncEnd;
203 kmode->vtotal = mode->VTotal;
204 kmode->vscan = mode->VScan;
206 kmode->flags = mode->Flags; //& FLAG_BITS;
208 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
209 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
213 drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
215 // FIXME - Implement this function
219 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
220 Rotation rotation, int x, int y)
222 ScrnInfoPtr pScrn = crtc->scrn;
223 OMAPPtr pOMAP = OMAPPTR(pScrn);
224 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
225 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
226 drmmode_ptr drmmode = drmmode_crtc->drmmode;
227 int saved_x, saved_y;
228 Rotation saved_rotation;
229 DisplayModeRec saved_mode;
230 uint32_t *output_ids = NULL;
231 int output_count = 0;
235 drmModeModeInfo kmode;
239 /* remove old fb if it exists */
240 drmmode_remove_fb(pScrn);
242 if (drmmode->fb_id == 0) {
244 OMAPCalculateStride(pScrn->virtualX, pScrn->bitsPerPixel);
246 DEBUG_MSG("create framebuffer: %dx%d",
247 pScrn->virtualX, pScrn->virtualY);
249 ret = drmModeAddFB(drmmode->fd,
250 pScrn->virtualX, pScrn->virtualY,
251 pScrn->depth, pScrn->bitsPerPixel,
252 pitch, omap_bo_handle(pOMAP->scanout),
255 // Fixme - improve this error message:
256 ErrorF("failed to add fb\n");
261 /* Save the current mode in case there's a problem: */
262 saved_mode = crtc->mode;
265 saved_rotation = crtc->rotation;
267 /* Set the new mode: */
271 crtc->rotation = rotation;
273 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
275 // Fixme - have an error message?
280 for (i = 0; i < xf86_config->num_output; i++) {
281 xf86OutputPtr output = xf86_config->output[i];
282 drmmode_output_private_ptr drmmode_output;
284 if (output->crtc != crtc)
287 drmmode_output = output->driver_private;
288 output_ids[output_count] =
289 drmmode_output->mode_output->connector_id;
293 if (!xf86CrtcRotate(crtc))
296 // Fixme - Intel puts this function here, and Nouveau puts it at the end
297 // of this function -> determine what's best for TI'S OMAP4:
298 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
299 crtc->gamma_blue, crtc->gamma_size);
301 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
303 fb_id = drmmode->fb_id;
305 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
306 fb_id, x, y, output_ids, output_count, &kmode);
308 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
309 "failed to set mode: %s\n", strerror(-ret));
314 // FIXME - DO WE NEED TO CALL TO THE PVR EXA/DRI2 CODE TO UPDATE THEM???
316 /* Turn on any outputs on this crtc that may have been disabled: */
317 for (i = 0; i < xf86_config->num_output; i++) {
318 xf86OutputPtr output = xf86_config->output[i];
320 if (output->crtc != crtc)
323 drmmode_output_dpms(output, DPMSModeOn);
326 // TODO: only call this if we are not using sw cursor.. ie. bad to call this
327 // if we haven't called xf86InitCursor()!!
328 // if (pScrn->pScreen)
329 // xf86_reload_cursors(pScrn->pScreen);
336 /* If there was a problem, resture the old mode: */
339 crtc->rotation = saved_rotation;
340 crtc->mode = saved_mode;
351 drmmode_hide_cursor(xf86CrtcPtr crtc)
353 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
354 drmmode_ptr drmmode = drmmode_crtc->drmmode;
355 drmmode_cursor_ptr cursor = drmmode->cursor;
360 cursor->visible = FALSE;
362 /* set plane's fb_id to 0 to disable it */
363 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
364 drmmode_crtc->mode_crtc->crtc_id, 0, 0,
365 0, 0, 0, 0, 0, 0, 0, 0);
369 drmmode_show_cursor(xf86CrtcPtr crtc)
371 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
372 drmmode_ptr drmmode = drmmode_crtc->drmmode;
373 drmmode_cursor_ptr cursor = drmmode->cursor;
374 int crtc_x, crtc_y, src_x, src_y, w, h;
379 cursor->visible = TRUE;
400 if ((crtc_x + w) > crtc->mode.HDisplay) {
401 w = crtc->mode.HDisplay - crtc_x;
404 if ((crtc_y + h) > crtc->mode.VDisplay) {
405 h = crtc->mode.VDisplay - crtc_y;
408 /* note src coords (last 4 args) are in Q16 format */
409 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
410 drmmode_crtc->mode_crtc->crtc_id, cursor->fb_id, 0,
411 crtc_x, crtc_y, w, h, src_x<<16, src_y<<16, w<<16, h<<16);
415 drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
417 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
418 drmmode_ptr drmmode = drmmode_crtc->drmmode;
419 drmmode_cursor_ptr cursor = drmmode->cursor;
428 drmmode_show_cursor(crtc);
432 drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
434 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
435 drmmode_ptr drmmode = drmmode_crtc->drmmode;
436 drmmode_cursor_ptr cursor = drmmode->cursor;
442 visible = cursor->visible;
445 drmmode_hide_cursor(crtc);
447 memcpy(omap_bo_map(cursor->bo), image, omap_bo_size(cursor->bo));
450 drmmode_show_cursor(crtc);
454 drmmode_cursor_init(ScreenPtr pScreen)
456 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
457 OMAPPtr pOMAP = OMAPPTR(pScrn);
458 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
459 drmmode_cursor_ptr cursor;
460 drmModePlaneRes *plane_resources;
463 /* technically we probably don't have any size limit.. since we
464 * are just using an overlay... but xserver will always create
465 * cursor images in the max size, so don't use width/height values
468 int w = CURSORW, h = CURSORH;
469 uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */
471 if (drmmode->cursor) {
472 INFO_MSG("cursor already initialized");
476 cursor = calloc(1, sizeof(drmmode_cursor_rec));
478 /* find an unused plane which can be used as a mouse cursor. Note
479 * that we cheat a bit, in order to not burn one overlay per crtc,
480 * and only show the mouse cursor on one crtc at a time
482 plane_resources = drmModeGetPlaneResources(drmmode->fd);
483 if (!plane_resources) {
484 ERROR_MSG("drmModeGetPlaneResources failed: %s", strerror(errno));
488 if (plane_resources->count_planes < 1) {
489 ERROR_MSG("not enough planes for HW cursor");
493 ovr = drmModeGetPlane(drmmode->fd, plane_resources->planes[0]);
495 ERROR_MSG("drmModeGetPlane failed: %s\n", strerror(errno));
500 cursor->bo = omap_bo_new(pOMAP->dev, w*h*4,
501 OMAP_BO_SCANOUT | OMAP_BO_WC);
503 handles[0] = omap_bo_handle(cursor->bo);
507 if (drmModeAddFB2(drmmode->fd, w, h, DRM_FORMAT_ARGB8888,
508 handles, pitches, offsets, &cursor->fb_id, 0)) {
509 ERROR_MSG("drmModeAddFB2 failed: %s", strerror(errno));
513 if (xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) {
514 INFO_MSG("HW cursor initialized");
515 drmmode->cursor = cursor;
519 // TODO cleanup when things fail..
524 drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
527 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
528 drmmode_ptr drmmode = drmmode_crtc->drmmode;
531 ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
532 size, red, green, blue);
534 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
535 "failed to set gamma: %s\n", strerror(-ret));
539 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
540 .dpms = drmmode_crtc_dpms,
541 .set_mode_major = drmmode_set_mode_major,
542 .set_cursor_position = drmmode_set_cursor_position,
543 .show_cursor = drmmode_show_cursor,
544 .hide_cursor = drmmode_hide_cursor,
545 .load_cursor_argb = drmmode_load_cursor_argb,
546 .gamma_set = drmmode_gamma_set,
551 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
554 drmmode_crtc_private_ptr drmmode_crtc;
558 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
562 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
563 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
564 drmmode->mode_res->crtcs[num]);
565 drmmode_crtc->drmmode = drmmode;
567 // FIXME - potentially add code to allocate a HW cursor here.
569 crtc->driver_private = drmmode_crtc;
575 static xf86OutputStatus
576 drmmode_output_detect(xf86OutputPtr output)
578 /* go to the hw and retrieve a new output struct */
579 drmmode_output_private_ptr drmmode_output = output->driver_private;
580 drmmode_ptr drmmode = drmmode_output->drmmode;
581 xf86OutputStatus status;
582 drmModeFreeConnector(drmmode_output->mode_output);
584 drmmode_output->mode_output =
585 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
587 switch (drmmode_output->mode_output->connection) {
588 case DRM_MODE_CONNECTED:
589 status = XF86OutputStatusConnected;
591 case DRM_MODE_DISCONNECTED:
592 status = XF86OutputStatusDisconnected;
595 case DRM_MODE_UNKNOWNCONNECTION:
596 status = XF86OutputStatusUnknown;
603 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
605 if (mode->type & M_T_DEFAULT)
606 /* Default modes are harmful here. */
612 static DisplayModePtr
613 drmmode_output_get_modes(xf86OutputPtr output)
615 ScrnInfoPtr pScrn = output->scrn;
616 drmmode_output_private_ptr drmmode_output = output->driver_private;
617 drmModeConnectorPtr koutput = drmmode_output->mode_output;
618 drmmode_ptr drmmode = drmmode_output->drmmode;
619 DisplayModePtr Modes = NULL, Mode;
620 drmModePropertyPtr props;
621 xf86MonPtr ddc_mon = NULL;
624 /* look for an EDID property */
625 for (i = 0; i < koutput->count_props; i++) {
626 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
627 if (!props || !(props->flags & DRM_MODE_PROP_BLOB))
630 if (!strcmp(props->name, "EDID")) {
631 if (drmmode_output->edid_blob)
632 drmModeFreePropertyBlob(drmmode_output->edid_blob);
633 drmmode_output->edid_blob =
634 drmModeGetPropertyBlob(drmmode->fd,
635 koutput->prop_values[i]);
637 drmModeFreeProperty(props);
640 if (drmmode_output->edid_blob)
641 ddc_mon = xf86InterpretEDID(pScrn->scrnIndex,
642 drmmode_output->edid_blob->data);
645 XF86_CRTC_CONFIG_PTR(pScrn)->debug_modes = TRUE;
646 xf86PrintEDID(ddc_mon);
647 xf86OutputSetEDID(output, ddc_mon);
648 xf86SetDDCproperties(pScrn, ddc_mon);
651 DEBUG_MSG("count_modes: %d", koutput->count_modes);
653 /* modes should already be available */
654 for (i = 0; i < koutput->count_modes; i++) {
655 Mode = xnfalloc(sizeof(DisplayModeRec));
657 drmmode_ConvertFromKMode(pScrn, &koutput->modes[i],
659 Modes = xf86ModesAdd(Modes, Mode);
666 drmmode_output_destroy(xf86OutputPtr output)
668 drmmode_output_private_ptr drmmode_output = output->driver_private;
671 if (drmmode_output->edid_blob)
672 drmModeFreePropertyBlob(drmmode_output->edid_blob);
673 for (i = 0; i < drmmode_output->num_props; i++) {
674 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
675 free(drmmode_output->props[i].atoms);
677 drmModeFreeConnector(drmmode_output->mode_output);
678 free(drmmode_output);
679 output->driver_private = NULL;
683 drmmode_output_dpms(xf86OutputPtr output, int mode)
685 drmmode_output_private_ptr drmmode_output = output->driver_private;
686 drmModeConnectorPtr koutput = drmmode_output->mode_output;
687 drmModePropertyPtr props;
688 drmmode_ptr drmmode = drmmode_output->drmmode;
691 for (i = 0; i < koutput->count_props; i++) {
692 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
693 if (props && (props->flags && DRM_MODE_PROP_ENUM)) {
694 if (!strcmp(props->name, "DPMS")) {
695 mode_id = koutput->props[i];
696 drmModeFreeProperty(props);
699 drmModeFreeProperty(props);
706 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
711 drmmode_property_ignore(drmModePropertyPtr prop)
715 /* ignore blob prop */
716 if (prop->flags & DRM_MODE_PROP_BLOB)
718 /* ignore standard property */
719 if (!strcmp(prop->name, "EDID") ||
720 !strcmp(prop->name, "DPMS"))
727 drmmode_output_create_resources(xf86OutputPtr output)
729 drmmode_output_private_ptr drmmode_output = output->driver_private;
730 drmModeConnectorPtr mode_output = drmmode_output->mode_output;
731 drmmode_ptr drmmode = drmmode_output->drmmode;
732 drmModePropertyPtr drmmode_prop;
736 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
737 if (!drmmode_output->props)
740 drmmode_output->num_props = 0;
741 for (i = 0, j = 0; i < mode_output->count_props; i++) {
742 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
743 if (drmmode_property_ignore(drmmode_prop)) {
744 drmModeFreeProperty(drmmode_prop);
747 drmmode_output->props[j].mode_prop = drmmode_prop;
748 drmmode_output->props[j].index = i;
749 drmmode_output->num_props++;
753 for (i = 0; i < drmmode_output->num_props; i++) {
754 drmmode_prop_ptr p = &drmmode_output->props[i];
755 drmmode_prop = p->mode_prop;
757 value = drmmode_output->mode_output->prop_values[p->index];
759 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
763 p->atoms = calloc(p->num_atoms, sizeof(Atom));
766 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
767 range[0] = drmmode_prop->values[0];
768 range[1] = drmmode_prop->values[1];
769 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
771 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
774 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
775 "RRConfigureOutputProperty error, %d\n", err);
777 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
778 XA_INTEGER, 32, PropModeReplace, 1,
779 &value, FALSE, FALSE);
781 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
782 "RRChangeOutputProperty error, %d\n", err);
784 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
785 p->num_atoms = drmmode_prop->count_enums + 1;
786 p->atoms = calloc(p->num_atoms, sizeof(Atom));
789 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
790 for (j = 1; j <= drmmode_prop->count_enums; j++) {
791 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
792 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
794 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
796 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
797 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
799 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
800 "RRConfigureOutputProperty error, %d\n", err);
802 for (j = 0; j < drmmode_prop->count_enums; j++)
803 if (drmmode_prop->enums[j].value == value)
805 /* there's always a matching value */
806 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
807 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
809 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
810 "RRChangeOutputProperty error, %d\n", err);
817 drmmode_output_set_property(xf86OutputPtr output, Atom property,
818 RRPropertyValuePtr value)
820 drmmode_output_private_ptr drmmode_output = output->driver_private;
821 drmmode_ptr drmmode = drmmode_output->drmmode;
824 for (i = 0; i < drmmode_output->num_props; i++) {
825 drmmode_prop_ptr p = &drmmode_output->props[i];
827 if (p->atoms[0] != property)
830 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
833 if (value->type != XA_INTEGER || value->format != 32 ||
836 val = *(uint32_t *)value->data;
838 ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
839 p->mode_prop->prop_id, (uint64_t)val);
846 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
851 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
853 memcpy(&atom, value->data, 4);
854 name = NameForAtom(atom);
856 /* search for matching name string, then set its value down */
857 for (j = 0; j < p->mode_prop->count_enums; j++) {
858 if (!strcmp(p->mode_prop->enums[j].name, name)) {
859 ret = drmModeConnectorSetProperty(drmmode->fd,
860 drmmode_output->output_id,
861 p->mode_prop->prop_id,
862 p->mode_prop->enums[j].value);
879 drmmode_output_get_property(xf86OutputPtr output, Atom property)
882 drmmode_output_private_ptr drmmode_output = output->driver_private;
883 drmmode_ptr drmmode = drmmode_output->drmmode;
887 if (output->scrn->vtSema) {
888 drmModeFreeConnector(drmmode_output->mode_output);
889 drmmode_output->mode_output =
890 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
893 for (i = 0; i < drmmode_output->num_props; i++) {
894 drmmode_prop_ptr p = &drmmode_output->props[i];
895 if (p->atoms[0] != property)
898 value = drmmode_output->mode_output->prop_values[p->index];
900 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
901 err = RRChangeOutputProperty(output->randr_output,
902 property, XA_INTEGER, 32,
903 PropModeReplace, 1, &value,
907 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
910 /* search for matching name string, then set its value down */
911 for (j = 0; j < p->mode_prop->count_enums; j++) {
912 if (p->mode_prop->enums[j].value == value)
916 err = RRChangeOutputProperty(output->randr_output, property,
917 XA_ATOM, 32, PropModeReplace, 1,
918 &p->atoms[j+1], FALSE, FALSE);
927 static const xf86OutputFuncsRec drmmode_output_funcs = {
928 .create_resources = drmmode_output_create_resources,
929 .dpms = drmmode_output_dpms,
930 .detect = drmmode_output_detect,
931 .mode_valid = drmmode_output_mode_valid,
932 .get_modes = drmmode_output_get_modes,
933 .set_property = drmmode_output_set_property,
934 .get_property = drmmode_output_get_property,
935 .destroy = drmmode_output_destroy
938 // FIXME - Eliminate the following values that aren't accurate for OMAP4:
939 const char *output_names[] = { "None",
955 #define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
958 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
960 xf86OutputPtr output;
961 drmModeConnectorPtr koutput;
962 drmModeEncoderPtr kencoder;
963 drmmode_output_private_ptr drmmode_output;
968 koutput = drmModeGetConnector(drmmode->fd,
969 drmmode->mode_res->connectors[num]);
973 kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
975 drmModeFreeConnector(koutput);
979 if (koutput->connector_type >= NUM_OUTPUT_NAMES)
980 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
981 koutput->connector_type_id);
983 snprintf(name, 32, "%s-%d",
984 output_names[koutput->connector_type],
985 koutput->connector_type_id);
987 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
989 drmModeFreeEncoder(kencoder);
990 drmModeFreeConnector(koutput);
994 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
995 if (!drmmode_output) {
996 xf86OutputDestroy(output);
997 drmModeFreeConnector(koutput);
998 drmModeFreeEncoder(kencoder);
1002 drmmode_output->output_id = drmmode->mode_res->connectors[num];
1003 drmmode_output->mode_output = koutput;
1004 drmmode_output->mode_encoder = kencoder;
1005 drmmode_output->drmmode = drmmode;
1007 output->mm_width = koutput->mmWidth;
1008 output->mm_height = koutput->mmHeight;
1009 output->driver_private = drmmode_output;
1011 output->possible_crtcs = kencoder->possible_crtcs;
1012 output->possible_clones = kencoder->possible_clones;
1013 output->interlaceAllowed = TRUE;
1020 drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
1022 OMAPPtr pOMAP = OMAPPTR(pScrn);
1023 ScreenPtr pScreen = pScrn->pScreen;
1028 /* if fb required size has changed, realloc! */
1030 DEBUG_MSG("Resize! %dx%d", width, height);
1032 pScrn->virtualX = width;
1033 pScrn->virtualY = height;
1035 pitch = OMAPCalculateStride(width, pScrn->bitsPerPixel);
1037 if ((pitch * height) != omap_bo_size(pOMAP->scanout)) {
1038 /* hmm, should we remove fb here.. we don't want to keep
1039 * scanning out a deallocated buffer..
1041 drmmode_remove_fb(pScrn);
1043 /* delete old scanout buffer */
1044 omap_bo_del(pOMAP->scanout);
1046 DEBUG_MSG("allocating new scanout buffer: %dx%d (%d)",
1047 width, height, pitch);
1049 /* allocate new scanout buffer */
1050 pOMAP->scanout = omap_bo_new(pOMAP->dev, height * pitch,
1051 OMAP_BO_SCANOUT | OMAP_BO_WC);
1052 if (!pOMAP->scanout) {
1053 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1054 "Error reallocating scanout buffer\n");
1059 if (pScreen && pScreen->ModifyPixmapHeader) {
1060 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1061 pScreen->ModifyPixmapHeader(rootPixmap,
1062 pScrn->virtualX, pScrn->virtualY,
1063 pScrn->depth, pScrn->bitsPerPixel, pitch,
1064 omap_bo_map(pOMAP->scanout));
1071 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
1072 drmmode_xf86crtc_resize
1076 Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
1078 drmmode_ptr drmmode;
1083 drmmode = calloc(1, sizeof *drmmode);
1087 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
1091 drmmode->mode_res = drmModeGetResources(drmmode->fd);
1092 if (!drmmode->mode_res) {
1095 DEBUG_MSG("Got KMS resources");
1096 DEBUG_MSG(" %d connectors, %d encoders",
1097 drmmode->mode_res->count_connectors,
1098 drmmode->mode_res->count_encoders);
1099 DEBUG_MSG(" %d crtcs, %d fbs",
1100 drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs);
1101 DEBUG_MSG(" %dx%d minimum resolution",
1102 drmmode->mode_res->min_width, drmmode->mode_res->min_height);
1103 DEBUG_MSG(" %dx%d maximum resolution",
1104 drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1106 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
1107 drmmode->mode_res->max_height);
1108 for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1109 drmmode_crtc_init(pScrn, drmmode, i);
1111 for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1112 drmmode_output_init(pScrn, drmmode, i);
1114 xf86InitialConfiguration(pScrn, TRUE);
1122 drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y, int flags)
1124 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1125 xf86OutputPtr output = config->output[config->compat_output];
1126 xf86CrtcPtr crtc = output->crtc;
1128 if (!crtc || !crtc->enabled)
1131 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
1135 drmmode_remove_fb(ScrnInfoPtr pScrn)
1137 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1138 xf86CrtcPtr crtc = NULL;
1139 drmmode_crtc_private_ptr drmmode_crtc;
1140 drmmode_ptr drmmode;
1143 crtc = config->crtc[0];
1147 drmmode_crtc = crtc->driver_private;
1148 drmmode = drmmode_crtc->drmmode;
1151 drmModeRmFB(drmmode->fd, drmmode->fb_id);
1160 page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
1161 unsigned int tv_usec, void *user_data)
1163 OMAPDRI2SwapComplete(user_data);
1166 static drmEventContext event_context = {
1167 .version = DRM_EVENT_CONTEXT_VERSION,
1168 .page_flip_handler = page_flip_handler,
1172 drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
1174 ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
1175 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1176 drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
1177 drmmode_ptr mode = crtc->drmmode;
1180 /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
1181 for (i = 0; i < config->num_crtc; i++) {
1182 crtc = config->crtc[i]->driver_private;
1184 if (!config->crtc[i]->enabled)
1187 ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
1188 fb_id, DRM_MODE_PAGE_FLIP_EVENT, priv);
1190 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1191 "flip queue failed: %s\n", strerror(errno));
1200 * Hot Plug Event handling:
1204 drmmode_handle_uevents(int fd, void *closure)
1206 ScrnInfoPtr pScrn = closure;
1207 OMAPPtr pOMAP = OMAPPTR(pScrn);
1208 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1209 struct udev_device *dev;
1210 const char *hotplug;
1214 dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1218 // FIXME - Do we need to keep this code, which Rob originally wrote
1219 // (i.e. up thru the "if" statement)?:
1222 * Check to make sure this event is directed at our
1223 * device (by comparing dev_t values), then make
1224 * sure it's a hotplug event (HOTPLUG=1)
1226 udev_devnum = udev_device_get_devnum(dev);
1227 fstat(pOMAP->drmFD, &s);
1229 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
1231 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug,
1232 memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)));
1234 if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
1235 hotplug && atoi(hotplug) == 1) {
1236 RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE);
1238 udev_device_unref(dev);
1242 drmmode_uevent_init(ScrnInfoPtr pScrn)
1244 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1246 struct udev_monitor *mon;
1253 mon = udev_monitor_new_from_netlink(u, "udev");
1259 if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1262 udev_monitor_enable_receiving(mon) < 0) {
1263 udev_monitor_unref(mon);
1268 drmmode->uevent_handler =
1269 xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1270 drmmode_handle_uevents, pScrn);
1272 drmmode->uevent_monitor = mon;
1278 drmmode_uevent_fini(ScrnInfoPtr pScrn)
1280 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1284 if (drmmode->uevent_handler) {
1285 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1286 xf86RemoveGeneralHandler(drmmode->uevent_handler);
1288 udev_monitor_unref(drmmode->uevent_monitor);
1296 drmmode_wakeup_handler(pointer data, int err, pointer p)
1298 ScrnInfoPtr pScrn = data;
1299 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1300 fd_set *read_mask = p;
1302 if (pScrn == NULL || err < 0)
1305 if (FD_ISSET(drmmode->fd, read_mask))
1306 drmHandleEvent(drmmode->fd, &event_context);
1310 drmmode_wait_for_event(ScrnInfoPtr pScrn)
1312 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1313 drmHandleEvent(drmmode->fd, &event_context);
1317 drmmode_screen_init(ScrnInfoPtr pScrn)
1319 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1321 drmmode_uevent_init(pScrn);
1323 AddGeneralSocket(drmmode->fd);
1325 /* Register a wakeup handler to get informed on DRM events */
1326 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1327 drmmode_wakeup_handler, pScrn);
1331 drmmode_screen_fini(ScrnInfoPtr pScrn)
1333 drmmode_uevent_fini(pScrn);