blob: 92f352dfe8b4a0caf49a77d067cf1e0134dc73bd [file] [log] [blame]
Rob Clark487687e2011-07-17 17:29:02 -05001/*
2 * Copyright © 2007 Red Hat, Inc.
3 * Copyright © 2008 Maarten Maathuis
4 * Copyright © 2011 Texas Instruments, Inc
5 *
6 *
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:
13 *
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
16 * Software.
17 *
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
24 * SOFTWARE.
25 *
26 * Authors:
27 * Dave Airlie <airlied@redhat.com>
28 * Ian Elliott <ianelliottus@yahoo.com>
29 */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
Rob Clark74210d52012-01-08 17:59:08 -060035/* TODO cleanup #includes, remove unnecessary ones */
36
Rob Clark487687e2011-07-17 17:29:02 -050037#include "xorgVersion.h"
38
Rob Clark487687e2011-07-17 17:29:02 -050039#include <sys/stat.h>
40
Rob Clark487687e2011-07-17 17:29:02 -050041#include <string.h>
42#include <math.h>
43#include <errno.h>
44#include <unistd.h>
45#include <stdlib.h>
46
47/* All drivers should typically include these */
48#include "xf86.h"
49#include "xf86_OSproc.h"
50#define PPC_MMIO_IS_BE
51#include "compiler.h"
Rob Clark487687e2011-07-17 17:29:02 -050052#include "mipointer.h"
53
54/* All drivers implementing backing store need this */
55#include "mibstore.h"
56
57#include "micmap.h"
58
59#include "xf86DDC.h"
60
61#include "vbe.h"
Rob Clark487687e2011-07-17 17:29:02 -050062#include "xf86RandR12.h"
Rob Clark487687e2011-07-17 17:29:02 -050063#include "dixstruct.h"
64#include "scrnintstr.h"
Rob Clark487687e2011-07-17 17:29:02 -050065#include "fb.h"
Rob Clark487687e2011-07-17 17:29:02 -050066#include "xf86cmap.h"
67#include "shadowfb.h"
68
69#include "xf86xv.h"
70#include <X11/extensions/Xv.h>
71
72#include "xf86Cursor.h"
73#include "xf86DDC.h"
74
75#include "region.h"
76
77#include <X11/extensions/randr.h>
78
79#ifdef HAVE_XEXTPROTO_71
80#include <X11/extensions/dpmsconst.h>
81#else
82#define DPMS_SERVER
83#include <X11/extensions/dpms.h>
84#endif
85
Rob Clark487687e2011-07-17 17:29:02 -050086#include "omap_driver.h"
87
Rob Clark487687e2011-07-17 17:29:02 -050088#include "xf86Crtc.h"
Rob Clark487687e2011-07-17 17:29:02 -050089
90#include "xf86drmMode.h"
Rob Clark687c6082012-01-08 19:33:18 -060091#include "drm_fourcc.h"
Rob Clark487687e2011-07-17 17:29:02 -050092#include "X11/Xatom.h"
93
94#include <sys/ioctl.h>
95#include <libudev.h>
96
97typedef struct {
Rob Clark687c6082012-01-08 19:33:18 -060098 /* hardware cursor: */
99 drmModePlane *ovr;
100 struct omap_bo *bo;
101 uint32_t fb_id;
102 int x, y;
103 int visible;
104} drmmode_cursor_rec, *drmmode_cursor_ptr;
105
106typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600107 int fd;
108 uint32_t fb_id;
109 drmModeResPtr mode_res;
110 int cpp;
111 struct udev_monitor *uevent_monitor;
112 InputHandlerProc uevent_handler;
Rob Clark687c6082012-01-08 19:33:18 -0600113 drmmode_cursor_ptr cursor;
Rob Clark487687e2011-07-17 17:29:02 -0500114} drmmode_rec, *drmmode_ptr;
115
116typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600117 drmmode_ptr drmmode;
118 drmModeCrtcPtr mode_crtc;
Rob Clark487687e2011-07-17 17:29:02 -0500119} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
120
121typedef struct {
122 drmModePropertyPtr mode_prop;
123 int index; /* Index within the kernel-side property arrays for
Rob Clark74210d52012-01-08 17:59:08 -0600124 * this connector. */
Rob Clark487687e2011-07-17 17:29:02 -0500125 int num_atoms; /* if range prop, num_atoms == 1; if enum prop,
Rob Clark74210d52012-01-08 17:59:08 -0600126 * num_atoms == num_enums + 1 */
Rob Clark487687e2011-07-17 17:29:02 -0500127 Atom *atoms;
128} drmmode_prop_rec, *drmmode_prop_ptr;
129
130typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600131 drmmode_ptr drmmode;
132 int output_id;
133 drmModeConnectorPtr mode_output;
134 drmModeEncoderPtr mode_encoder;
135 drmModePropertyBlobPtr edid_blob;
136 int num_props;
137 drmmode_prop_ptr props;
Rob Clark487687e2011-07-17 17:29:02 -0500138} drmmode_output_private_rec, *drmmode_output_private_ptr;
139
140static void drmmode_output_dpms(xf86OutputPtr output, int mode);
141void drmmode_remove_fb(ScrnInfoPtr pScrn);
142
Rob Clark687c6082012-01-08 19:33:18 -0600143static drmmode_ptr
144drmmode_from_scrn(ScrnInfoPtr pScrn)
145{
146 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
147 drmmode_crtc_private_ptr drmmode_crtc;
148
149 drmmode_crtc = xf86_config->crtc[0]->driver_private;
150 return drmmode_crtc->drmmode;
151}
152
Rob Clark487687e2011-07-17 17:29:02 -0500153static void
154drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600155 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500156{
Rob Clark74210d52012-01-08 17:59:08 -0600157 memset(mode, 0, sizeof(DisplayModeRec));
158 mode->status = MODE_OK;
Rob Clark487687e2011-07-17 17:29:02 -0500159
Rob Clark74210d52012-01-08 17:59:08 -0600160 mode->Clock = kmode->clock;
Rob Clark487687e2011-07-17 17:29:02 -0500161
Rob Clark74210d52012-01-08 17:59:08 -0600162 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;
Rob Clark487687e2011-07-17 17:29:02 -0500167
Rob Clark74210d52012-01-08 17:59:08 -0600168 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;
Rob Clark487687e2011-07-17 17:29:02 -0500173
Rob Clark74210d52012-01-08 17:59:08 -0600174 mode->Flags = kmode->flags; //& FLAG_BITS;
175 mode->name = strdup(kmode->name);
Rob Clark487687e2011-07-17 17:29:02 -0500176
Rob Clark74210d52012-01-08 17:59:08 -0600177 DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500178
Rob Clark74210d52012-01-08 17:59:08 -0600179 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;
Rob Clark487687e2011-07-17 17:29:02 -0500183
Rob Clark74210d52012-01-08 17:59:08 -0600184 xf86SetModeCrtc (mode, pScrn->adjustFlags);
185}
Rob Clark487687e2011-07-17 17:29:02 -0500186
187static void
188drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600189 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500190{
Rob Clark74210d52012-01-08 17:59:08 -0600191 memset(kmode, 0, sizeof(*kmode));
Rob Clark487687e2011-07-17 17:29:02 -0500192
Rob Clark74210d52012-01-08 17:59:08 -0600193 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;
Rob Clark487687e2011-07-17 17:29:02 -0500199
Rob Clark74210d52012-01-08 17:59:08 -0600200 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;
Rob Clark487687e2011-07-17 17:29:02 -0500205
Rob Clark74210d52012-01-08 17:59:08 -0600206 kmode->flags = mode->Flags; //& FLAG_BITS;
207 if (mode->name)
208 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
209 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
210}
Rob Clark487687e2011-07-17 17:29:02 -0500211
212static void
213drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
214{
Rob Clark74210d52012-01-08 17:59:08 -0600215 // FIXME - Implement this function
216}
Rob Clark487687e2011-07-17 17:29:02 -0500217
218static Bool
219drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rob Clark74210d52012-01-08 17:59:08 -0600220 Rotation rotation, int x, int y)
Rob Clark487687e2011-07-17 17:29:02 -0500221{
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;
232 int ret = TRUE;
233 int i;
234 int fb_id;
235 drmModeModeInfo kmode;
236
237 TRACE_ENTER();
238
239 /* remove old fb if it exists */
240 drmmode_remove_fb(pScrn);
241
242 if (drmmode->fb_id == 0) {
243 unsigned int pitch =
244 OMAPCalculateStride(pScrn->virtualX, pScrn->bitsPerPixel);
245
246 DEBUG_MSG("create framebuffer: %dx%d",
247 pScrn->virtualX, pScrn->virtualY);
248
249 ret = drmModeAddFB(drmmode->fd,
250 pScrn->virtualX, pScrn->virtualY,
251 pScrn->depth, pScrn->bitsPerPixel,
252 pitch, omap_bo_handle(pOMAP->scanout),
253 &drmmode->fb_id);
254 if (ret < 0) {
255 // Fixme - improve this error message:
256 ErrorF("failed to add fb\n");
257 return FALSE;
258 }
259 }
260
261 /* Save the current mode in case there's a problem: */
262 saved_mode = crtc->mode;
263 saved_x = crtc->x;
264 saved_y = crtc->y;
265 saved_rotation = crtc->rotation;
266
267 /* Set the new mode: */
268 crtc->mode = *mode;
269 crtc->x = x;
270 crtc->y = y;
271 crtc->rotation = rotation;
272
273 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
274 if (!output_ids) {
275 // Fixme - have an error message?
276 ret = FALSE;
277 goto done;
278 }
279
280 for (i = 0; i < xf86_config->num_output; i++) {
281 xf86OutputPtr output = xf86_config->output[i];
282 drmmode_output_private_ptr drmmode_output;
283
284 if (output->crtc != crtc)
285 continue;
286
287 drmmode_output = output->driver_private;
288 output_ids[output_count] =
289 drmmode_output->mode_output->connector_id;
290 output_count++;
291 }
292
293 if (!xf86CrtcRotate(crtc))
294 goto done;
295
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);
300
301 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
302
303 fb_id = drmmode->fb_id;
Rob Clark74210d52012-01-08 17:59:08 -0600304
Rob Clark487687e2011-07-17 17:29:02 -0500305 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
306 fb_id, x, y, output_ids, output_count, &kmode);
307 if (ret) {
308 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
309 "failed to set mode: %s\n", strerror(-ret));
310 } else {
311 ret = TRUE;
312 }
313
314 // FIXME - DO WE NEED TO CALL TO THE PVR EXA/DRI2 CODE TO UPDATE THEM???
315
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];
319
320 if (output->crtc != crtc)
321 continue;
322
323 drmmode_output_dpms(output, DPMSModeOn);
324 }
325
Rob Clark74210d52012-01-08 17:59:08 -0600326 // 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);
Rob Clark487687e2011-07-17 17:29:02 -0500330
331done:
332 if (output_ids) {
333 free(output_ids);
334 }
335 if (!ret) {
336 /* If there was a problem, resture the old mode: */
337 crtc->x = saved_x;
338 crtc->y = saved_y;
339 crtc->rotation = saved_rotation;
340 crtc->mode = saved_mode;
341 }
342
343 TRACE_EXIT();
344 return ret;
Rob Clark74210d52012-01-08 17:59:08 -0600345}
Rob Clark487687e2011-07-17 17:29:02 -0500346
Rob Clark60f5bad2012-01-22 18:35:28 -0600347#define CURSORW 64
348#define CURSORH 64
349
Rob Clark487687e2011-07-17 17:29:02 -0500350static void
Rob Clark487687e2011-07-17 17:29:02 -0500351drmmode_hide_cursor(xf86CrtcPtr crtc)
352{
Rob Clark74210d52012-01-08 17:59:08 -0600353 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
354 drmmode_ptr drmmode = drmmode_crtc->drmmode;
Rob Clark687c6082012-01-08 19:33:18 -0600355 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark487687e2011-07-17 17:29:02 -0500356
Rob Clark687c6082012-01-08 19:33:18 -0600357 if (!cursor)
358 return;
359
360 cursor->visible = FALSE;
361
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);
Rob Clark74210d52012-01-08 17:59:08 -0600366}
Rob Clark487687e2011-07-17 17:29:02 -0500367
368static void
369drmmode_show_cursor(xf86CrtcPtr crtc)
370{
Rob Clark74210d52012-01-08 17:59:08 -0600371 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
372 drmmode_ptr drmmode = drmmode_crtc->drmmode;
Rob Clark687c6082012-01-08 19:33:18 -0600373 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark60f5bad2012-01-22 18:35:28 -0600374 int crtc_x, crtc_y, src_x, src_y, w, h;
Rob Clark487687e2011-07-17 17:29:02 -0500375
Rob Clark687c6082012-01-08 19:33:18 -0600376 if (!cursor)
377 return;
Rob Clark487687e2011-07-17 17:29:02 -0500378
Rob Clark687c6082012-01-08 19:33:18 -0600379 cursor->visible = TRUE;
380
Rob Clark60f5bad2012-01-22 18:35:28 -0600381 w = CURSORW;
382 h = CURSORH;
383 crtc_x = cursor->x;
384 crtc_y = cursor->y;
385 src_x = 0;
386 src_y = 0;
387
388 if (crtc_x < 0) {
389 src_x += -crtc_x;
390 w -= -crtc_x;
391 crtc_x = 0;
392 }
393
394 if (crtc_y < 0) {
395 src_y += -crtc_y;
396 h -= -crtc_y;
397 crtc_y = 0;
398 }
399
400 if ((crtc_x + w) > crtc->mode.HDisplay) {
401 w = crtc->mode.HDisplay - crtc_x;
402 }
403
404 if ((crtc_y + h) > crtc->mode.VDisplay) {
405 h = crtc->mode.VDisplay - crtc_y;
406 }
407
Rob Clark687c6082012-01-08 19:33:18 -0600408 /* 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,
Rob Clark60f5bad2012-01-22 18:35:28 -0600411 crtc_x, crtc_y, w, h, src_x<<16, src_y<<16, w<<16, h<<16);
Rob Clark687c6082012-01-08 19:33:18 -0600412}
413
414static void
415drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
416{
417 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
418 drmmode_ptr drmmode = drmmode_crtc->drmmode;
419 drmmode_cursor_ptr cursor = drmmode->cursor;
420
421 if (!cursor)
422 return;
423
424 cursor->x = x;
425 cursor->y = y;
426
427 if (cursor->visible)
428 drmmode_show_cursor(crtc);
429}
430
431static void
432drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
433{
434 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
435 drmmode_ptr drmmode = drmmode_crtc->drmmode;
436 drmmode_cursor_ptr cursor = drmmode->cursor;
437
438 if (!cursor)
439 return;
440
441 if (cursor->visible)
442 drmmode_hide_cursor(crtc);
443
444 memcpy(omap_bo_map(cursor->bo), image, omap_bo_size(cursor->bo));
445
446 if (cursor->visible)
447 drmmode_show_cursor(crtc);
448}
449
450Bool
451drmmode_cursor_init(ScreenPtr pScreen)
452{
453 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
454 OMAPPtr pOMAP = OMAPPTR(pScrn);
455 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
456 drmmode_cursor_ptr cursor;
457 drmModePlaneRes *plane_resources;
458 drmModePlane *ovr;
459
460 /* technically we probably don't have any size limit.. since we
461 * are just using an overlay... but xserver will always create
462 * cursor images in the max size, so don't use width/height values
463 * that are too big
464 */
Rob Clark60f5bad2012-01-22 18:35:28 -0600465 int w = CURSORW, h = CURSORH;
Rob Clark687c6082012-01-08 19:33:18 -0600466 uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */
467
468 if (drmmode->cursor) {
469 INFO_MSG("cursor already initialized");
470 return TRUE;
471 }
472
473 cursor = calloc(1, sizeof(drmmode_cursor_rec));
474
475 /* find an unused plane which can be used as a mouse cursor. Note
476 * that we cheat a bit, in order to not burn one overlay per crtc,
477 * and only show the mouse cursor on one crtc at a time
478 */
479 plane_resources = drmModeGetPlaneResources(drmmode->fd);
480 if (!plane_resources) {
481 ERROR_MSG("drmModeGetPlaneResources failed: %s", strerror(errno));
482 return FALSE;
483 }
484
485 if (plane_resources->count_planes < 1) {
486 ERROR_MSG("not enough planes for HW cursor");
487 return FALSE;
488 }
489
490 ovr = drmModeGetPlane(drmmode->fd, plane_resources->planes[0]);
491 if (!ovr) {
492 ERROR_MSG("drmModeGetPlane failed: %s\n", strerror(errno));
493 return FALSE;
494 }
495
496 cursor->ovr = ovr;
497 cursor->bo = omap_bo_new(pOMAP->dev, w*h*4,
498 OMAP_BO_SCANOUT | OMAP_BO_WC);
499
500 handles[0] = omap_bo_handle(cursor->bo);
501 pitches[0] = w*4;
502 offsets[0] = 0;
503
504 if (drmModeAddFB2(drmmode->fd, w, h, DRM_FORMAT_ARGB8888,
505 handles, pitches, offsets, &cursor->fb_id, 0)) {
506 ERROR_MSG("drmModeAddFB2 failed: %s", strerror(errno));
507 return FALSE;
508 }
509
510 if (xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) {
511 INFO_MSG("HW cursor initialized");
512 drmmode->cursor = cursor;
513 return TRUE;
514 }
515
516 // TODO cleanup when things fail..
517 return FALSE;
Rob Clark74210d52012-01-08 17:59:08 -0600518}
Rob Clark487687e2011-07-17 17:29:02 -0500519
520static void
521drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
Rob Clark74210d52012-01-08 17:59:08 -0600522 int size)
Rob Clark487687e2011-07-17 17:29:02 -0500523{
524 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
525 drmmode_ptr drmmode = drmmode_crtc->drmmode;
526 int ret;
527
528 ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
Rob Clark74210d52012-01-08 17:59:08 -0600529 size, red, green, blue);
Rob Clark487687e2011-07-17 17:29:02 -0500530 if (ret != 0) {
531 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600532 "failed to set gamma: %s\n", strerror(-ret));
Rob Clark487687e2011-07-17 17:29:02 -0500533 }
534}
535
536static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600537 .dpms = drmmode_crtc_dpms,
538 .set_mode_major = drmmode_set_mode_major,
539 .set_cursor_position = drmmode_set_cursor_position,
540 .show_cursor = drmmode_show_cursor,
541 .hide_cursor = drmmode_hide_cursor,
542 .load_cursor_argb = drmmode_load_cursor_argb,
543 .gamma_set = drmmode_gamma_set,
Rob Clark487687e2011-07-17 17:29:02 -0500544};
545
546
547static void
548drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
549{
Rob Clark74210d52012-01-08 17:59:08 -0600550 xf86CrtcPtr crtc;
551 drmmode_crtc_private_ptr drmmode_crtc;
Rob Clark487687e2011-07-17 17:29:02 -0500552
Rob Clark74210d52012-01-08 17:59:08 -0600553 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -0500554
Rob Clark74210d52012-01-08 17:59:08 -0600555 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
556 if (crtc == NULL)
557 return;
558
559 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
560 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
561 drmmode->mode_res->crtcs[num]);
562 drmmode_crtc->drmmode = drmmode;
563
564 // FIXME - potentially add code to allocate a HW cursor here.
565
566 crtc->driver_private = drmmode_crtc;
567
568 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -0500569 return;
Rob Clark74210d52012-01-08 17:59:08 -0600570}
Rob Clark487687e2011-07-17 17:29:02 -0500571
572static xf86OutputStatus
573drmmode_output_detect(xf86OutputPtr output)
574{
575 /* go to the hw and retrieve a new output struct */
576 drmmode_output_private_ptr drmmode_output = output->driver_private;
577 drmmode_ptr drmmode = drmmode_output->drmmode;
578 xf86OutputStatus status;
579 drmModeFreeConnector(drmmode_output->mode_output);
580
581 drmmode_output->mode_output =
Rob Clark74210d52012-01-08 17:59:08 -0600582 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500583
584 switch (drmmode_output->mode_output->connection) {
585 case DRM_MODE_CONNECTED:
586 status = XF86OutputStatusConnected;
587 break;
588 case DRM_MODE_DISCONNECTED:
589 status = XF86OutputStatusDisconnected;
590 break;
591 default:
592 case DRM_MODE_UNKNOWNCONNECTION:
593 status = XF86OutputStatusUnknown;
594 break;
595 }
596 return status;
597}
598
599static Bool
600drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
601{
602 if (mode->type & M_T_DEFAULT)
603 /* Default modes are harmful here. */
604 return MODE_BAD;
605
606 return MODE_OK;
607}
608
609static DisplayModePtr
610drmmode_output_get_modes(xf86OutputPtr output)
611{
612 ScrnInfoPtr pScrn = output->scrn;
613 drmmode_output_private_ptr drmmode_output = output->driver_private;
614 drmModeConnectorPtr koutput = drmmode_output->mode_output;
615 drmmode_ptr drmmode = drmmode_output->drmmode;
616 DisplayModePtr Modes = NULL, Mode;
617 drmModePropertyPtr props;
618 xf86MonPtr ddc_mon = NULL;
619 int i;
620
621 /* look for an EDID property */
622 for (i = 0; i < koutput->count_props; i++) {
623 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
624 if (!props || !(props->flags & DRM_MODE_PROP_BLOB))
625 continue;
626
627 if (!strcmp(props->name, "EDID")) {
628 if (drmmode_output->edid_blob)
629 drmModeFreePropertyBlob(drmmode_output->edid_blob);
630 drmmode_output->edid_blob =
Rob Clark74210d52012-01-08 17:59:08 -0600631 drmModeGetPropertyBlob(drmmode->fd,
632 koutput->prop_values[i]);
Rob Clark487687e2011-07-17 17:29:02 -0500633 }
634 drmModeFreeProperty(props);
635 }
636
637 if (drmmode_output->edid_blob)
638 ddc_mon = xf86InterpretEDID(pScrn->scrnIndex,
Rob Clark74210d52012-01-08 17:59:08 -0600639 drmmode_output->edid_blob->data);
Rob Clark487687e2011-07-17 17:29:02 -0500640
641 if (ddc_mon) {
Rob Clark74210d52012-01-08 17:59:08 -0600642 XF86_CRTC_CONFIG_PTR(pScrn)->debug_modes = TRUE;
Rob Clark487687e2011-07-17 17:29:02 -0500643 xf86PrintEDID(ddc_mon);
644 xf86OutputSetEDID(output, ddc_mon);
645 xf86SetDDCproperties(pScrn, ddc_mon);
646 }
647
648 DEBUG_MSG("count_modes: %d", koutput->count_modes);
649
650 /* modes should already be available */
651 for (i = 0; i < koutput->count_modes; i++) {
652 Mode = xnfalloc(sizeof(DisplayModeRec));
653
654 drmmode_ConvertFromKMode(pScrn, &koutput->modes[i],
Rob Clark74210d52012-01-08 17:59:08 -0600655 Mode);
Rob Clark487687e2011-07-17 17:29:02 -0500656 Modes = xf86ModesAdd(Modes, Mode);
657
658 }
659 return Modes;
660}
661
662static void
663drmmode_output_destroy(xf86OutputPtr output)
664{
665 drmmode_output_private_ptr drmmode_output = output->driver_private;
666 int i;
667
668 if (drmmode_output->edid_blob)
669 drmModeFreePropertyBlob(drmmode_output->edid_blob);
670 for (i = 0; i < drmmode_output->num_props; i++) {
671 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
672 free(drmmode_output->props[i].atoms);
673 }
674 drmModeFreeConnector(drmmode_output->mode_output);
675 free(drmmode_output);
676 output->driver_private = NULL;
677}
678
679static void
680drmmode_output_dpms(xf86OutputPtr output, int mode)
681{
682 drmmode_output_private_ptr drmmode_output = output->driver_private;
683 drmModeConnectorPtr koutput = drmmode_output->mode_output;
684 drmModePropertyPtr props;
685 drmmode_ptr drmmode = drmmode_output->drmmode;
686 int mode_id = -1, i;
687
688 for (i = 0; i < koutput->count_props; i++) {
689 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
690 if (props && (props->flags && DRM_MODE_PROP_ENUM)) {
691 if (!strcmp(props->name, "DPMS")) {
692 mode_id = koutput->props[i];
693 drmModeFreeProperty(props);
694 break;
695 }
696 drmModeFreeProperty(props);
697 }
698 }
699
700 if (mode_id < 0)
701 return;
702
703 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
Rob Clark74210d52012-01-08 17:59:08 -0600704 mode_id, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500705}
706
707static Bool
708drmmode_property_ignore(drmModePropertyPtr prop)
709{
710 if (!prop)
Rob Clark74210d52012-01-08 17:59:08 -0600711 return TRUE;
Rob Clark487687e2011-07-17 17:29:02 -0500712 /* ignore blob prop */
713 if (prop->flags & DRM_MODE_PROP_BLOB)
714 return TRUE;
715 /* ignore standard property */
716 if (!strcmp(prop->name, "EDID") ||
Rob Clark74210d52012-01-08 17:59:08 -0600717 !strcmp(prop->name, "DPMS"))
Rob Clark487687e2011-07-17 17:29:02 -0500718 return TRUE;
719
720 return FALSE;
721}
722
723static void
724drmmode_output_create_resources(xf86OutputPtr output)
725{
726 drmmode_output_private_ptr drmmode_output = output->driver_private;
727 drmModeConnectorPtr mode_output = drmmode_output->mode_output;
728 drmmode_ptr drmmode = drmmode_output->drmmode;
729 drmModePropertyPtr drmmode_prop;
730 uint32_t value;
731 int i, j, err;
732
733 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
734 if (!drmmode_output->props)
735 return;
736
737 drmmode_output->num_props = 0;
738 for (i = 0, j = 0; i < mode_output->count_props; i++) {
739 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
740 if (drmmode_property_ignore(drmmode_prop)) {
741 drmModeFreeProperty(drmmode_prop);
742 continue;
743 }
744 drmmode_output->props[j].mode_prop = drmmode_prop;
745 drmmode_output->props[j].index = i;
746 drmmode_output->num_props++;
747 j++;
748 }
749
750 for (i = 0; i < drmmode_output->num_props; i++) {
751 drmmode_prop_ptr p = &drmmode_output->props[i];
752 drmmode_prop = p->mode_prop;
753
754 value = drmmode_output->mode_output->prop_values[p->index];
755
756 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
757 INT32 range[2];
758
759 p->num_atoms = 1;
760 p->atoms = calloc(p->num_atoms, sizeof(Atom));
761 if (!p->atoms)
762 continue;
763 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
764 range[0] = drmmode_prop->values[0];
765 range[1] = drmmode_prop->values[1];
766 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600767 FALSE, TRUE,
768 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
Rob Clark487687e2011-07-17 17:29:02 -0500769 2, range);
770 if (err != 0) {
771 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600772 "RRConfigureOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500773 }
774 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600775 XA_INTEGER, 32, PropModeReplace, 1,
776 &value, FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500777 if (err != 0) {
778 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600779 "RRChangeOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500780 }
781 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
782 p->num_atoms = drmmode_prop->count_enums + 1;
783 p->atoms = calloc(p->num_atoms, sizeof(Atom));
784 if (!p->atoms)
785 continue;
786 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
787 for (j = 1; j <= drmmode_prop->count_enums; j++) {
788 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
789 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
790 }
791 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600792 FALSE, FALSE,
793 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
Rob Clark487687e2011-07-17 17:29:02 -0500794 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
795 if (err != 0) {
796 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600797 "RRConfigureOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500798 }
799 for (j = 0; j < drmmode_prop->count_enums; j++)
800 if (drmmode_prop->enums[j].value == value)
801 break;
802 /* there's always a matching value */
803 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600804 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500805 if (err != 0) {
806 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600807 "RRChangeOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500808 }
809 }
810 }
811}
812
813static Bool
814drmmode_output_set_property(xf86OutputPtr output, Atom property,
Rob Clark74210d52012-01-08 17:59:08 -0600815 RRPropertyValuePtr value)
Rob Clark487687e2011-07-17 17:29:02 -0500816{
817 drmmode_output_private_ptr drmmode_output = output->driver_private;
818 drmmode_ptr drmmode = drmmode_output->drmmode;
819 int i, ret;
820
821 for (i = 0; i < drmmode_output->num_props; i++) {
822 drmmode_prop_ptr p = &drmmode_output->props[i];
823
824 if (p->atoms[0] != property)
825 continue;
826
827 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
828 uint32_t val;
829
830 if (value->type != XA_INTEGER || value->format != 32 ||
Rob Clark74210d52012-01-08 17:59:08 -0600831 value->size != 1)
Rob Clark487687e2011-07-17 17:29:02 -0500832 return FALSE;
833 val = *(uint32_t *)value->data;
834
835 ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
Rob Clark74210d52012-01-08 17:59:08 -0600836 p->mode_prop->prop_id, (uint64_t)val);
Rob Clark487687e2011-07-17 17:29:02 -0500837
838 if (ret)
839 return FALSE;
840
841 return TRUE;
842
843 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
844 Atom atom;
845 const char *name;
846 int j;
847
848 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
849 return FALSE;
850 memcpy(&atom, value->data, 4);
851 name = NameForAtom(atom);
852
853 /* search for matching name string, then set its value down */
854 for (j = 0; j < p->mode_prop->count_enums; j++) {
855 if (!strcmp(p->mode_prop->enums[j].name, name)) {
856 ret = drmModeConnectorSetProperty(drmmode->fd,
Rob Clark74210d52012-01-08 17:59:08 -0600857 drmmode_output->output_id,
858 p->mode_prop->prop_id,
859 p->mode_prop->enums[j].value);
Rob Clark487687e2011-07-17 17:29:02 -0500860
861 if (ret)
862 return FALSE;
863
864 return TRUE;
865 }
866 }
867
868 return FALSE;
869 }
870 }
871
872 return TRUE;
873}
874
875static Bool
876drmmode_output_get_property(xf86OutputPtr output, Atom property)
877{
878
879 drmmode_output_private_ptr drmmode_output = output->driver_private;
880 drmmode_ptr drmmode = drmmode_output->drmmode;
881 uint32_t value;
882 int err, i;
883
884 if (output->scrn->vtSema) {
885 drmModeFreeConnector(drmmode_output->mode_output);
886 drmmode_output->mode_output =
Rob Clark74210d52012-01-08 17:59:08 -0600887 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500888 }
889
890 for (i = 0; i < drmmode_output->num_props; i++) {
891 drmmode_prop_ptr p = &drmmode_output->props[i];
892 if (p->atoms[0] != property)
893 continue;
894
895 value = drmmode_output->mode_output->prop_values[p->index];
896
897 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
898 err = RRChangeOutputProperty(output->randr_output,
Rob Clark74210d52012-01-08 17:59:08 -0600899 property, XA_INTEGER, 32,
900 PropModeReplace, 1, &value,
901 FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500902
903 return !err;
904 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
905 int j;
906
907 /* search for matching name string, then set its value down */
908 for (j = 0; j < p->mode_prop->count_enums; j++) {
909 if (p->mode_prop->enums[j].value == value)
910 break;
911 }
912
913 err = RRChangeOutputProperty(output->randr_output, property,
Rob Clark74210d52012-01-08 17:59:08 -0600914 XA_ATOM, 32, PropModeReplace, 1,
915 &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500916
917 return !err;
918 }
919 }
920
921 return FALSE;
922}
923
924static const xf86OutputFuncsRec drmmode_output_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600925 .create_resources = drmmode_output_create_resources,
926 .dpms = drmmode_output_dpms,
927 .detect = drmmode_output_detect,
928 .mode_valid = drmmode_output_mode_valid,
929 .get_modes = drmmode_output_get_modes,
930 .set_property = drmmode_output_set_property,
931 .get_property = drmmode_output_get_property,
932 .destroy = drmmode_output_destroy
Rob Clark487687e2011-07-17 17:29:02 -0500933};
934
935// FIXME - Eliminate the following values that aren't accurate for OMAP4:
936const char *output_names[] = { "None",
Rob Clark74210d52012-01-08 17:59:08 -0600937 "VGA",
938 "DVI-I",
939 "DVI-D",
940 "DVI-A",
941 "Composite",
942 "SVIDEO",
943 "LVDS",
944 "CTV",
945 "DIN",
946 "DP",
947 "HDMI",
948 "HDMI",
949 "TV",
950 "eDP",
Rob Clark487687e2011-07-17 17:29:02 -0500951};
952#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
953
954static void
955drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
956{
Rob Clark74210d52012-01-08 17:59:08 -0600957 xf86OutputPtr output;
958 drmModeConnectorPtr koutput;
959 drmModeEncoderPtr kencoder;
960 drmmode_output_private_ptr drmmode_output;
961 char name[32];
Rob Clark487687e2011-07-17 17:29:02 -0500962
Rob Clark74210d52012-01-08 17:59:08 -0600963 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -0500964
Rob Clark74210d52012-01-08 17:59:08 -0600965 koutput = drmModeGetConnector(drmmode->fd,
966 drmmode->mode_res->connectors[num]);
967 if (!koutput)
968 return;
Rob Clark487687e2011-07-17 17:29:02 -0500969
Rob Clark74210d52012-01-08 17:59:08 -0600970 kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
971 if (!kencoder) {
972 drmModeFreeConnector(koutput);
973 return;
974 }
Rob Clark487687e2011-07-17 17:29:02 -0500975
Rob Clark74210d52012-01-08 17:59:08 -0600976 if (koutput->connector_type >= NUM_OUTPUT_NAMES)
977 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
978 koutput->connector_type_id);
979 else
980 snprintf(name, 32, "%s-%d",
981 output_names[koutput->connector_type],
982 koutput->connector_type_id);
Rob Clark487687e2011-07-17 17:29:02 -0500983
Rob Clark74210d52012-01-08 17:59:08 -0600984 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
985 if (!output) {
986 drmModeFreeEncoder(kencoder);
987 drmModeFreeConnector(koutput);
988 return;
989 }
Rob Clark487687e2011-07-17 17:29:02 -0500990
Rob Clark74210d52012-01-08 17:59:08 -0600991 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
992 if (!drmmode_output) {
993 xf86OutputDestroy(output);
994 drmModeFreeConnector(koutput);
995 drmModeFreeEncoder(kencoder);
996 return;
997 }
Rob Clark487687e2011-07-17 17:29:02 -0500998
Rob Clark74210d52012-01-08 17:59:08 -0600999 drmmode_output->output_id = drmmode->mode_res->connectors[num];
1000 drmmode_output->mode_output = koutput;
1001 drmmode_output->mode_encoder = kencoder;
1002 drmmode_output->drmmode = drmmode;
Rob Clark487687e2011-07-17 17:29:02 -05001003
Rob Clark74210d52012-01-08 17:59:08 -06001004 output->mm_width = koutput->mmWidth;
1005 output->mm_height = koutput->mmHeight;
1006 output->driver_private = drmmode_output;
Rob Clark487687e2011-07-17 17:29:02 -05001007
Rob Clark74210d52012-01-08 17:59:08 -06001008 output->possible_crtcs = kencoder->possible_crtcs;
1009 output->possible_clones = kencoder->possible_clones;
1010 output->interlaceAllowed = TRUE;
Rob Clark487687e2011-07-17 17:29:02 -05001011
Rob Clark74210d52012-01-08 17:59:08 -06001012 TRACE_EXIT();
1013 return;
1014}
Rob Clark487687e2011-07-17 17:29:02 -05001015
1016static Bool
1017drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
1018{
1019 OMAPPtr pOMAP = OMAPPTR(pScrn);
1020 ScreenPtr pScreen = pScrn->pScreen;
1021 unsigned int pitch;
1022
1023 TRACE_ENTER();
1024
1025 /* if fb required size has changed, realloc! */
1026
1027 DEBUG_MSG("Resize! %dx%d", width, height);
1028
1029 pScrn->virtualX = width;
1030 pScrn->virtualY = height;
1031
1032 pitch = OMAPCalculateStride(width, pScrn->bitsPerPixel);
1033
1034 if ((pitch * height) != omap_bo_size(pOMAP->scanout)) {
1035 /* hmm, should we remove fb here.. we don't want to keep
1036 * scanning out a deallocated buffer..
1037 */
1038 drmmode_remove_fb(pScrn);
1039
1040 /* delete old scanout buffer */
1041 omap_bo_del(pOMAP->scanout);
1042
1043 DEBUG_MSG("allocating new scanout buffer: %dx%d (%d)",
1044 width, height, pitch);
1045
1046 /* allocate new scanout buffer */
1047 pOMAP->scanout = omap_bo_new(pOMAP->dev, height * pitch,
1048 OMAP_BO_SCANOUT | OMAP_BO_WC);
1049 if (!pOMAP->scanout) {
1050 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1051 "Error reallocating scanout buffer\n");
1052 return FALSE;
1053 }
1054 }
1055
1056 if (pScreen && pScreen->ModifyPixmapHeader) {
1057 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1058 pScreen->ModifyPixmapHeader(rootPixmap,
1059 pScrn->virtualX, pScrn->virtualY,
1060 pScrn->depth, pScrn->bitsPerPixel, pitch,
1061 omap_bo_map(pOMAP->scanout));
1062 }
1063
1064 TRACE_EXIT();
1065 return TRUE;
Rob Clark74210d52012-01-08 17:59:08 -06001066}
Rob Clark487687e2011-07-17 17:29:02 -05001067
1068static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -06001069 drmmode_xf86crtc_resize
Rob Clark487687e2011-07-17 17:29:02 -05001070};
1071
1072
1073Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
1074{
Rob Clark74210d52012-01-08 17:59:08 -06001075 drmmode_ptr drmmode;
1076 int i;
Rob Clark487687e2011-07-17 17:29:02 -05001077
Rob Clark74210d52012-01-08 17:59:08 -06001078 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001079
Rob Clark74210d52012-01-08 17:59:08 -06001080 drmmode = calloc(1, sizeof *drmmode);
1081 drmmode->fd = fd;
1082 drmmode->fb_id = 0;
Rob Clark487687e2011-07-17 17:29:02 -05001083
Rob Clark74210d52012-01-08 17:59:08 -06001084 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
Rob Clark487687e2011-07-17 17:29:02 -05001085
1086
Rob Clark74210d52012-01-08 17:59:08 -06001087 drmmode->cpp = cpp;
1088 drmmode->mode_res = drmModeGetResources(drmmode->fd);
1089 if (!drmmode->mode_res) {
1090 return FALSE;
1091 } else {
1092 DEBUG_MSG("Got KMS resources");
1093 DEBUG_MSG(" %d connectors, %d encoders",
1094 drmmode->mode_res->count_connectors,
1095 drmmode->mode_res->count_encoders);
1096 DEBUG_MSG(" %d crtcs, %d fbs",
1097 drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs);
1098 DEBUG_MSG(" %dx%d minimum resolution",
1099 drmmode->mode_res->min_width, drmmode->mode_res->min_height);
1100 DEBUG_MSG(" %dx%d maximum resolution",
1101 drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1102 }
1103 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
1104 drmmode->mode_res->max_height);
1105 for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1106 drmmode_crtc_init(pScrn, drmmode, i);
Rob Clark487687e2011-07-17 17:29:02 -05001107
Rob Clark74210d52012-01-08 17:59:08 -06001108 for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1109 drmmode_output_init(pScrn, drmmode, i);
Rob Clark487687e2011-07-17 17:29:02 -05001110
Rob Clark74210d52012-01-08 17:59:08 -06001111 xf86InitialConfiguration(pScrn, TRUE);
Rob Clark487687e2011-07-17 17:29:02 -05001112
Rob Clark74210d52012-01-08 17:59:08 -06001113 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -05001114
Rob Clark74210d52012-01-08 17:59:08 -06001115 return TRUE;
1116}
Rob Clark487687e2011-07-17 17:29:02 -05001117
1118void
1119drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y, int flags)
1120{
1121 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1122 xf86OutputPtr output = config->output[config->compat_output];
1123 xf86CrtcPtr crtc = output->crtc;
1124
1125 if (!crtc || !crtc->enabled)
1126 return;
1127
1128 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
1129}
1130
1131void
1132drmmode_remove_fb(ScrnInfoPtr pScrn)
1133{
1134 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1135 xf86CrtcPtr crtc = NULL;
1136 drmmode_crtc_private_ptr drmmode_crtc;
1137 drmmode_ptr drmmode;
1138
1139 if (config)
1140 crtc = config->crtc[0];
1141 if (!crtc)
1142 return;
1143
1144 drmmode_crtc = crtc->driver_private;
1145 drmmode = drmmode_crtc->drmmode;
1146
1147 if (drmmode->fb_id)
1148 drmModeRmFB(drmmode->fd, drmmode->fb_id);
1149 drmmode->fb_id = 0;
1150}
1151
Rob Clark4b8f30a2011-08-28 12:51:26 -05001152/*
1153 * Page Flipping
1154 */
1155
1156static void
1157page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
Rob Clark74210d52012-01-08 17:59:08 -06001158 unsigned int tv_usec, void *user_data)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001159{
Rob Clark4b8f30a2011-08-28 12:51:26 -05001160 OMAPDRI2SwapComplete(user_data);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001161}
1162
1163static drmEventContext event_context = {
1164 .version = DRM_EVENT_CONTEXT_VERSION,
1165 .page_flip_handler = page_flip_handler,
1166};
1167
1168Bool
1169drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
1170{
1171 ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
1172 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1173 drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
1174 drmmode_ptr mode = crtc->drmmode;
1175 int ret, i;
1176
1177 /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
1178 for (i = 0; i < config->num_crtc; i++) {
1179 crtc = config->crtc[i]->driver_private;
1180
1181 if (!config->crtc[i]->enabled)
1182 continue;
1183
1184 ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
1185 fb_id, DRM_MODE_PAGE_FLIP_EVENT, priv);
1186 if (ret) {
1187 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
Rob Clark74210d52012-01-08 17:59:08 -06001188 "flip queue failed: %s\n", strerror(errno));
Rob Clark4b8f30a2011-08-28 12:51:26 -05001189 return FALSE;
1190 }
1191 }
1192
1193 return TRUE;
1194}
Rob Clark487687e2011-07-17 17:29:02 -05001195
1196/*
1197 * Hot Plug Event handling:
1198 */
1199
Rob Clark487687e2011-07-17 17:29:02 -05001200static void
1201drmmode_handle_uevents(int fd, void *closure)
1202{
Rob Clark74210d52012-01-08 17:59:08 -06001203 ScrnInfoPtr pScrn = closure;
1204 OMAPPtr pOMAP = OMAPPTR(pScrn);
1205 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1206 struct udev_device *dev;
1207 const char *hotplug;
1208 struct stat s;
1209 dev_t udev_devnum;
Rob Clark487687e2011-07-17 17:29:02 -05001210
Rob Clark74210d52012-01-08 17:59:08 -06001211 dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1212 if (!dev)
1213 return;
Rob Clark487687e2011-07-17 17:29:02 -05001214
Rob Clark74210d52012-01-08 17:59:08 -06001215 // FIXME - Do we need to keep this code, which Rob originally wrote
1216 // (i.e. up thru the "if" statement)?:
Rob Clark487687e2011-07-17 17:29:02 -05001217
Rob Clark74210d52012-01-08 17:59:08 -06001218 /*
1219 * Check to make sure this event is directed at our
1220 * device (by comparing dev_t values), then make
1221 * sure it's a hotplug event (HOTPLUG=1)
1222 */
1223 udev_devnum = udev_device_get_devnum(dev);
1224 fstat(pOMAP->drmFD, &s);
Rob Clark487687e2011-07-17 17:29:02 -05001225
Rob Clark74210d52012-01-08 17:59:08 -06001226 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
Rob Clark487687e2011-07-17 17:29:02 -05001227
Rob Clark74210d52012-01-08 17:59:08 -06001228 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug,
1229 memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)));
Rob Clark487687e2011-07-17 17:29:02 -05001230
Rob Clark74210d52012-01-08 17:59:08 -06001231 if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
1232 hotplug && atoi(hotplug) == 1) {
1233 RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE);
1234 }
1235 udev_device_unref(dev);
1236}
Rob Clark487687e2011-07-17 17:29:02 -05001237
Rob Clark4b8f30a2011-08-28 12:51:26 -05001238static void
Rob Clark487687e2011-07-17 17:29:02 -05001239drmmode_uevent_init(ScrnInfoPtr pScrn)
1240{
Rob Clark74210d52012-01-08 17:59:08 -06001241 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1242 struct udev *u;
1243 struct udev_monitor *mon;
Rob Clark487687e2011-07-17 17:29:02 -05001244
Rob Clark74210d52012-01-08 17:59:08 -06001245 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001246
Rob Clark74210d52012-01-08 17:59:08 -06001247 u = udev_new();
1248 if (!u)
1249 return;
1250 mon = udev_monitor_new_from_netlink(u, "udev");
1251 if (!mon) {
1252 udev_unref(u);
1253 return;
1254 }
Rob Clark487687e2011-07-17 17:29:02 -05001255
Rob Clark74210d52012-01-08 17:59:08 -06001256 if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1257 "drm",
1258 "drm_minor") < 0 ||
1259 udev_monitor_enable_receiving(mon) < 0) {
1260 udev_monitor_unref(mon);
1261 udev_unref(u);
1262 return;
1263 }
Rob Clark487687e2011-07-17 17:29:02 -05001264
Rob Clark74210d52012-01-08 17:59:08 -06001265 drmmode->uevent_handler =
1266 xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1267 drmmode_handle_uevents, pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001268
Rob Clark74210d52012-01-08 17:59:08 -06001269 drmmode->uevent_monitor = mon;
Rob Clark487687e2011-07-17 17:29:02 -05001270
Rob Clark74210d52012-01-08 17:59:08 -06001271 TRACE_EXIT();
1272}
Rob Clark487687e2011-07-17 17:29:02 -05001273
Rob Clark4b8f30a2011-08-28 12:51:26 -05001274static void
Rob Clark487687e2011-07-17 17:29:02 -05001275drmmode_uevent_fini(ScrnInfoPtr pScrn)
1276{
Rob Clark74210d52012-01-08 17:59:08 -06001277 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001278
Rob Clark74210d52012-01-08 17:59:08 -06001279 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001280
Rob Clark74210d52012-01-08 17:59:08 -06001281 if (drmmode->uevent_handler) {
1282 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1283 xf86RemoveGeneralHandler(drmmode->uevent_handler);
Rob Clark487687e2011-07-17 17:29:02 -05001284
Rob Clark74210d52012-01-08 17:59:08 -06001285 udev_monitor_unref(drmmode->uevent_monitor);
1286 udev_unref(u);
1287 }
Rob Clark487687e2011-07-17 17:29:02 -05001288
Rob Clark74210d52012-01-08 17:59:08 -06001289 TRACE_EXIT();
1290}
Rob Clark4b8f30a2011-08-28 12:51:26 -05001291
1292static void
1293drmmode_wakeup_handler(pointer data, int err, pointer p)
1294{
1295 ScrnInfoPtr scrn = data;
1296 drmmode_ptr drmmode = drmmode_from_scrn(scrn);
1297 fd_set *read_mask = p;
1298
1299 if (scrn == NULL || err < 0)
1300 return;
1301
1302 if (FD_ISSET(drmmode->fd, read_mask))
1303 drmHandleEvent(drmmode->fd, &event_context);
1304}
1305
1306void
1307drmmode_screen_init(ScrnInfoPtr pScrn)
1308{
Rob Clark74210d52012-01-08 17:59:08 -06001309 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001310
1311 drmmode_uevent_init(pScrn);
1312
Rob Clark74210d52012-01-08 17:59:08 -06001313 AddGeneralSocket(drmmode->fd);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001314
Rob Clark74210d52012-01-08 17:59:08 -06001315 /* Register a wakeup handler to get informed on DRM events */
1316 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1317 drmmode_wakeup_handler, pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001318}
1319
1320void
1321drmmode_screen_fini(ScrnInfoPtr pScrn)
1322{
1323 drmmode_uevent_fini(pScrn);
1324}