blob: ffe224195e75e8e7bd8d9350703cffc189434019 [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
Raymond Smithcb4c0372012-03-29 10:44:27 +010037#include "xorg-server.h"
Rob Clark487687e2011-07-17 17:29:02 -050038#include "xorgVersion.h"
39
Rob Clark487687e2011-07-17 17:29:02 -050040#include <sys/stat.h>
41
Rob Clark487687e2011-07-17 17:29:02 -050042#include <string.h>
43#include <math.h>
44#include <errno.h>
45#include <unistd.h>
46#include <stdlib.h>
47
48/* All drivers should typically include these */
49#include "xf86.h"
50#include "xf86_OSproc.h"
51#define PPC_MMIO_IS_BE
52#include "compiler.h"
Rob Clark487687e2011-07-17 17:29:02 -050053#include "mipointer.h"
54
55/* All drivers implementing backing store need this */
56#include "mibstore.h"
57
58#include "micmap.h"
59
60#include "xf86DDC.h"
61
62#include "vbe.h"
Rob Clark487687e2011-07-17 17:29:02 -050063#include "xf86RandR12.h"
Rob Clark487687e2011-07-17 17:29:02 -050064#include "dixstruct.h"
65#include "scrnintstr.h"
Rob Clark487687e2011-07-17 17:29:02 -050066#include "fb.h"
Rob Clark487687e2011-07-17 17:29:02 -050067#include "xf86cmap.h"
68#include "shadowfb.h"
69
70#include "xf86xv.h"
71#include <X11/extensions/Xv.h>
72
73#include "xf86Cursor.h"
74#include "xf86DDC.h"
75
76#include "region.h"
77
78#include <X11/extensions/randr.h>
79
80#ifdef HAVE_XEXTPROTO_71
81#include <X11/extensions/dpmsconst.h>
82#else
83#define DPMS_SERVER
84#include <X11/extensions/dpms.h>
85#endif
86
Rob Clark487687e2011-07-17 17:29:02 -050087#include "omap_driver.h"
88
Rob Clark487687e2011-07-17 17:29:02 -050089#include "xf86Crtc.h"
Rob Clark487687e2011-07-17 17:29:02 -050090
91#include "xf86drmMode.h"
Rob Clark687c6082012-01-08 19:33:18 -060092#include "drm_fourcc.h"
Rob Clark487687e2011-07-17 17:29:02 -050093#include "X11/Xatom.h"
94
95#include <sys/ioctl.h>
96#include <libudev.h>
97
98typedef struct {
Rob Clark687c6082012-01-08 19:33:18 -060099 /* hardware cursor: */
100 drmModePlane *ovr;
101 struct omap_bo *bo;
102 uint32_t fb_id;
103 int x, y;
104 int visible;
105} drmmode_cursor_rec, *drmmode_cursor_ptr;
106
107typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600108 int fd;
Rob Clark74210d52012-01-08 17:59:08 -0600109 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);
Rob Clark487687e2011-07-17 17:29:02 -0500141
Rob Clark687c6082012-01-08 19:33:18 -0600142static drmmode_ptr
143drmmode_from_scrn(ScrnInfoPtr pScrn)
144{
145 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
146 drmmode_crtc_private_ptr drmmode_crtc;
147
148 drmmode_crtc = xf86_config->crtc[0]->driver_private;
149 return drmmode_crtc->drmmode;
150}
151
Rob Clark487687e2011-07-17 17:29:02 -0500152static void
153drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600154 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500155{
Rob Clark74210d52012-01-08 17:59:08 -0600156 memset(mode, 0, sizeof(DisplayModeRec));
157 mode->status = MODE_OK;
Rob Clark487687e2011-07-17 17:29:02 -0500158
Rob Clark74210d52012-01-08 17:59:08 -0600159 mode->Clock = kmode->clock;
Rob Clark487687e2011-07-17 17:29:02 -0500160
Rob Clark74210d52012-01-08 17:59:08 -0600161 mode->HDisplay = kmode->hdisplay;
162 mode->HSyncStart = kmode->hsync_start;
163 mode->HSyncEnd = kmode->hsync_end;
164 mode->HTotal = kmode->htotal;
165 mode->HSkew = kmode->hskew;
Rob Clark487687e2011-07-17 17:29:02 -0500166
Rob Clark74210d52012-01-08 17:59:08 -0600167 mode->VDisplay = kmode->vdisplay;
168 mode->VSyncStart = kmode->vsync_start;
169 mode->VSyncEnd = kmode->vsync_end;
170 mode->VTotal = kmode->vtotal;
171 mode->VScan = kmode->vscan;
Rob Clark487687e2011-07-17 17:29:02 -0500172
Rob Clark74210d52012-01-08 17:59:08 -0600173 mode->Flags = kmode->flags; //& FLAG_BITS;
174 mode->name = strdup(kmode->name);
Rob Clark487687e2011-07-17 17:29:02 -0500175
Rob Clark74210d52012-01-08 17:59:08 -0600176 DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500177
Rob Clark74210d52012-01-08 17:59:08 -0600178 if (kmode->type & DRM_MODE_TYPE_DRIVER)
179 mode->type = M_T_DRIVER;
180 if (kmode->type & DRM_MODE_TYPE_PREFERRED)
181 mode->type |= M_T_PREFERRED;
Rob Clark487687e2011-07-17 17:29:02 -0500182
Rob Clark74210d52012-01-08 17:59:08 -0600183 xf86SetModeCrtc (mode, pScrn->adjustFlags);
184}
Rob Clark487687e2011-07-17 17:29:02 -0500185
186static void
187drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600188 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500189{
Rob Clark74210d52012-01-08 17:59:08 -0600190 memset(kmode, 0, sizeof(*kmode));
Rob Clark487687e2011-07-17 17:29:02 -0500191
Rob Clark74210d52012-01-08 17:59:08 -0600192 kmode->clock = mode->Clock;
193 kmode->hdisplay = mode->HDisplay;
194 kmode->hsync_start = mode->HSyncStart;
195 kmode->hsync_end = mode->HSyncEnd;
196 kmode->htotal = mode->HTotal;
197 kmode->hskew = mode->HSkew;
Rob Clark487687e2011-07-17 17:29:02 -0500198
Rob Clark74210d52012-01-08 17:59:08 -0600199 kmode->vdisplay = mode->VDisplay;
200 kmode->vsync_start = mode->VSyncStart;
201 kmode->vsync_end = mode->VSyncEnd;
202 kmode->vtotal = mode->VTotal;
203 kmode->vscan = mode->VScan;
Rob Clark487687e2011-07-17 17:29:02 -0500204
Rob Clark74210d52012-01-08 17:59:08 -0600205 kmode->flags = mode->Flags; //& FLAG_BITS;
206 if (mode->name)
207 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
208 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
209}
Rob Clark487687e2011-07-17 17:29:02 -0500210
211static void
212drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
213{
Rob Clark74210d52012-01-08 17:59:08 -0600214 // FIXME - Implement this function
215}
Rob Clark487687e2011-07-17 17:29:02 -0500216
217static Bool
218drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rob Clark74210d52012-01-08 17:59:08 -0600219 Rotation rotation, int x, int y)
Rob Clark487687e2011-07-17 17:29:02 -0500220{
221 ScrnInfoPtr pScrn = crtc->scrn;
222 OMAPPtr pOMAP = OMAPPTR(pScrn);
223 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
224 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
225 drmmode_ptr drmmode = drmmode_crtc->drmmode;
226 int saved_x, saved_y;
227 Rotation saved_rotation;
228 DisplayModeRec saved_mode;
229 uint32_t *output_ids = NULL;
230 int output_count = 0;
231 int ret = TRUE;
232 int i;
233 int fb_id;
234 drmModeModeInfo kmode;
235
236 TRACE_ENTER();
237
Rob Clark487687e2011-07-17 17:29:02 -0500238
239 /* Save the current mode in case there's a problem: */
240 saved_mode = crtc->mode;
241 saved_x = crtc->x;
242 saved_y = crtc->y;
243 saved_rotation = crtc->rotation;
244
245 /* Set the new mode: */
246 crtc->mode = *mode;
247 crtc->x = x;
248 crtc->y = y;
249 crtc->rotation = rotation;
250
251 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
252 if (!output_ids) {
253 // Fixme - have an error message?
254 ret = FALSE;
255 goto done;
256 }
257
258 for (i = 0; i < xf86_config->num_output; i++) {
259 xf86OutputPtr output = xf86_config->output[i];
260 drmmode_output_private_ptr drmmode_output;
261
262 if (output->crtc != crtc)
263 continue;
264
265 drmmode_output = output->driver_private;
266 output_ids[output_count] =
267 drmmode_output->mode_output->connector_id;
268 output_count++;
269 }
270
271 if (!xf86CrtcRotate(crtc))
272 goto done;
273
274 // Fixme - Intel puts this function here, and Nouveau puts it at the end
275 // of this function -> determine what's best for TI'S OMAP4:
276 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
277 crtc->gamma_blue, crtc->gamma_size);
278
279 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
280
David Garbett7d6a6e72012-05-11 11:52:45 +0100281 fb_id = omap_bo_get_fb(pOMAP->scanout);
Rob Clark74210d52012-01-08 17:59:08 -0600282
Rob Clark487687e2011-07-17 17:29:02 -0500283 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
284 fb_id, x, y, output_ids, output_count, &kmode);
285 if (ret) {
286 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
287 "failed to set mode: %s\n", strerror(-ret));
288 } else {
289 ret = TRUE;
290 }
291
292 // FIXME - DO WE NEED TO CALL TO THE PVR EXA/DRI2 CODE TO UPDATE THEM???
293
294 /* Turn on any outputs on this crtc that may have been disabled: */
295 for (i = 0; i < xf86_config->num_output; i++) {
296 xf86OutputPtr output = xf86_config->output[i];
297
298 if (output->crtc != crtc)
299 continue;
300
301 drmmode_output_dpms(output, DPMSModeOn);
302 }
303
Rob Clark74210d52012-01-08 17:59:08 -0600304 // TODO: only call this if we are not using sw cursor.. ie. bad to call this
305 // if we haven't called xf86InitCursor()!!
306 // if (pScrn->pScreen)
307 // xf86_reload_cursors(pScrn->pScreen);
Rob Clark487687e2011-07-17 17:29:02 -0500308
309done:
310 if (output_ids) {
311 free(output_ids);
312 }
313 if (!ret) {
314 /* If there was a problem, resture the old mode: */
315 crtc->x = saved_x;
316 crtc->y = saved_y;
317 crtc->rotation = saved_rotation;
318 crtc->mode = saved_mode;
319 }
320
321 TRACE_EXIT();
322 return ret;
Rob Clark74210d52012-01-08 17:59:08 -0600323}
Rob Clark487687e2011-07-17 17:29:02 -0500324
Rob Clark60f5bad2012-01-22 18:35:28 -0600325#define CURSORW 64
326#define CURSORH 64
327
Rob Clark487687e2011-07-17 17:29:02 -0500328static void
Rob Clark487687e2011-07-17 17:29:02 -0500329drmmode_hide_cursor(xf86CrtcPtr crtc)
330{
Rob Clark74210d52012-01-08 17:59:08 -0600331 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
332 drmmode_ptr drmmode = drmmode_crtc->drmmode;
Rob Clark687c6082012-01-08 19:33:18 -0600333 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark487687e2011-07-17 17:29:02 -0500334
Rob Clark687c6082012-01-08 19:33:18 -0600335 if (!cursor)
336 return;
337
338 cursor->visible = FALSE;
339
340 /* set plane's fb_id to 0 to disable it */
341 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
342 drmmode_crtc->mode_crtc->crtc_id, 0, 0,
343 0, 0, 0, 0, 0, 0, 0, 0);
Rob Clark74210d52012-01-08 17:59:08 -0600344}
Rob Clark487687e2011-07-17 17:29:02 -0500345
346static void
347drmmode_show_cursor(xf86CrtcPtr crtc)
348{
Rob Clark74210d52012-01-08 17:59:08 -0600349 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
350 drmmode_ptr drmmode = drmmode_crtc->drmmode;
Rob Clark687c6082012-01-08 19:33:18 -0600351 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark60f5bad2012-01-22 18:35:28 -0600352 int crtc_x, crtc_y, src_x, src_y, w, h;
Rob Clark487687e2011-07-17 17:29:02 -0500353
Rob Clark687c6082012-01-08 19:33:18 -0600354 if (!cursor)
355 return;
Rob Clark487687e2011-07-17 17:29:02 -0500356
Rob Clark687c6082012-01-08 19:33:18 -0600357 cursor->visible = TRUE;
358
Rob Clark60f5bad2012-01-22 18:35:28 -0600359 w = CURSORW;
360 h = CURSORH;
361 crtc_x = cursor->x;
362 crtc_y = cursor->y;
363 src_x = 0;
364 src_y = 0;
365
366 if (crtc_x < 0) {
367 src_x += -crtc_x;
368 w -= -crtc_x;
369 crtc_x = 0;
370 }
371
372 if (crtc_y < 0) {
373 src_y += -crtc_y;
374 h -= -crtc_y;
375 crtc_y = 0;
376 }
377
378 if ((crtc_x + w) > crtc->mode.HDisplay) {
379 w = crtc->mode.HDisplay - crtc_x;
380 }
381
382 if ((crtc_y + h) > crtc->mode.VDisplay) {
383 h = crtc->mode.VDisplay - crtc_y;
384 }
385
Rob Clark687c6082012-01-08 19:33:18 -0600386 /* note src coords (last 4 args) are in Q16 format */
387 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
388 drmmode_crtc->mode_crtc->crtc_id, cursor->fb_id, 0,
Rob Clark60f5bad2012-01-22 18:35:28 -0600389 crtc_x, crtc_y, w, h, src_x<<16, src_y<<16, w<<16, h<<16);
Rob Clark687c6082012-01-08 19:33:18 -0600390}
391
392static void
393drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
394{
395 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
396 drmmode_ptr drmmode = drmmode_crtc->drmmode;
397 drmmode_cursor_ptr cursor = drmmode->cursor;
398
399 if (!cursor)
400 return;
401
402 cursor->x = x;
403 cursor->y = y;
404
405 if (cursor->visible)
406 drmmode_show_cursor(crtc);
407}
408
409static void
410drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
411{
412 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
413 drmmode_ptr drmmode = drmmode_crtc->drmmode;
414 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark979add52012-02-21 18:35:24 -0600415 int visible;
Rob Clark687c6082012-01-08 19:33:18 -0600416
417 if (!cursor)
418 return;
419
Rob Clark979add52012-02-21 18:35:24 -0600420 visible = cursor->visible;
421
422 if (visible)
Rob Clark687c6082012-01-08 19:33:18 -0600423 drmmode_hide_cursor(crtc);
424
425 memcpy(omap_bo_map(cursor->bo), image, omap_bo_size(cursor->bo));
426
Rob Clark979add52012-02-21 18:35:24 -0600427 if (visible)
Rob Clark687c6082012-01-08 19:33:18 -0600428 drmmode_show_cursor(crtc);
429}
430
431Bool
432drmmode_cursor_init(ScreenPtr pScreen)
433{
434 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
435 OMAPPtr pOMAP = OMAPPTR(pScrn);
436 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
437 drmmode_cursor_ptr cursor;
438 drmModePlaneRes *plane_resources;
439 drmModePlane *ovr;
440
441 /* technically we probably don't have any size limit.. since we
442 * are just using an overlay... but xserver will always create
443 * cursor images in the max size, so don't use width/height values
444 * that are too big
445 */
Rob Clark60f5bad2012-01-22 18:35:28 -0600446 int w = CURSORW, h = CURSORH;
Rob Clark687c6082012-01-08 19:33:18 -0600447 uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */
448
449 if (drmmode->cursor) {
450 INFO_MSG("cursor already initialized");
451 return TRUE;
452 }
453
454 cursor = calloc(1, sizeof(drmmode_cursor_rec));
455
456 /* find an unused plane which can be used as a mouse cursor. Note
457 * that we cheat a bit, in order to not burn one overlay per crtc,
458 * and only show the mouse cursor on one crtc at a time
459 */
460 plane_resources = drmModeGetPlaneResources(drmmode->fd);
461 if (!plane_resources) {
462 ERROR_MSG("drmModeGetPlaneResources failed: %s", strerror(errno));
463 return FALSE;
464 }
465
466 if (plane_resources->count_planes < 1) {
467 ERROR_MSG("not enough planes for HW cursor");
468 return FALSE;
469 }
470
471 ovr = drmModeGetPlane(drmmode->fd, plane_resources->planes[0]);
472 if (!ovr) {
473 ERROR_MSG("drmModeGetPlane failed: %s\n", strerror(errno));
474 return FALSE;
475 }
476
477 cursor->ovr = ovr;
478 cursor->bo = omap_bo_new(pOMAP->dev, w*h*4,
479 OMAP_BO_SCANOUT | OMAP_BO_WC);
480
481 handles[0] = omap_bo_handle(cursor->bo);
482 pitches[0] = w*4;
483 offsets[0] = 0;
484
485 if (drmModeAddFB2(drmmode->fd, w, h, DRM_FORMAT_ARGB8888,
486 handles, pitches, offsets, &cursor->fb_id, 0)) {
487 ERROR_MSG("drmModeAddFB2 failed: %s", strerror(errno));
488 return FALSE;
489 }
490
491 if (xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) {
492 INFO_MSG("HW cursor initialized");
493 drmmode->cursor = cursor;
494 return TRUE;
495 }
496
497 // TODO cleanup when things fail..
498 return FALSE;
Rob Clark74210d52012-01-08 17:59:08 -0600499}
Rob Clark487687e2011-07-17 17:29:02 -0500500
501static void
502drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
Rob Clark74210d52012-01-08 17:59:08 -0600503 int size)
Rob Clark487687e2011-07-17 17:29:02 -0500504{
505 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
506 drmmode_ptr drmmode = drmmode_crtc->drmmode;
507 int ret;
508
509 ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
Rob Clark74210d52012-01-08 17:59:08 -0600510 size, red, green, blue);
Rob Clark487687e2011-07-17 17:29:02 -0500511 if (ret != 0) {
512 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600513 "failed to set gamma: %s\n", strerror(-ret));
Rob Clark487687e2011-07-17 17:29:02 -0500514 }
515}
516
517static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600518 .dpms = drmmode_crtc_dpms,
519 .set_mode_major = drmmode_set_mode_major,
520 .set_cursor_position = drmmode_set_cursor_position,
521 .show_cursor = drmmode_show_cursor,
522 .hide_cursor = drmmode_hide_cursor,
523 .load_cursor_argb = drmmode_load_cursor_argb,
524 .gamma_set = drmmode_gamma_set,
Rob Clark487687e2011-07-17 17:29:02 -0500525};
526
527
528static void
529drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
530{
Rob Clark74210d52012-01-08 17:59:08 -0600531 xf86CrtcPtr crtc;
532 drmmode_crtc_private_ptr drmmode_crtc;
Rob Clark487687e2011-07-17 17:29:02 -0500533
Rob Clark74210d52012-01-08 17:59:08 -0600534 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -0500535
Rob Clark74210d52012-01-08 17:59:08 -0600536 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
537 if (crtc == NULL)
538 return;
539
540 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
541 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
542 drmmode->mode_res->crtcs[num]);
543 drmmode_crtc->drmmode = drmmode;
544
545 // FIXME - potentially add code to allocate a HW cursor here.
546
547 crtc->driver_private = drmmode_crtc;
548
549 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -0500550 return;
Rob Clark74210d52012-01-08 17:59:08 -0600551}
Rob Clark487687e2011-07-17 17:29:02 -0500552
553static xf86OutputStatus
554drmmode_output_detect(xf86OutputPtr output)
555{
556 /* go to the hw and retrieve a new output struct */
557 drmmode_output_private_ptr drmmode_output = output->driver_private;
558 drmmode_ptr drmmode = drmmode_output->drmmode;
559 xf86OutputStatus status;
560 drmModeFreeConnector(drmmode_output->mode_output);
561
562 drmmode_output->mode_output =
Rob Clark74210d52012-01-08 17:59:08 -0600563 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500564
565 switch (drmmode_output->mode_output->connection) {
566 case DRM_MODE_CONNECTED:
567 status = XF86OutputStatusConnected;
568 break;
569 case DRM_MODE_DISCONNECTED:
570 status = XF86OutputStatusDisconnected;
571 break;
572 default:
573 case DRM_MODE_UNKNOWNCONNECTION:
574 status = XF86OutputStatusUnknown;
575 break;
576 }
577 return status;
578}
579
580static Bool
581drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
582{
583 if (mode->type & M_T_DEFAULT)
584 /* Default modes are harmful here. */
585 return MODE_BAD;
586
587 return MODE_OK;
588}
589
590static DisplayModePtr
591drmmode_output_get_modes(xf86OutputPtr output)
592{
593 ScrnInfoPtr pScrn = output->scrn;
594 drmmode_output_private_ptr drmmode_output = output->driver_private;
595 drmModeConnectorPtr koutput = drmmode_output->mode_output;
596 drmmode_ptr drmmode = drmmode_output->drmmode;
597 DisplayModePtr Modes = NULL, Mode;
598 drmModePropertyPtr props;
599 xf86MonPtr ddc_mon = NULL;
600 int i;
601
602 /* look for an EDID property */
603 for (i = 0; i < koutput->count_props; i++) {
604 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
605 if (!props || !(props->flags & DRM_MODE_PROP_BLOB))
606 continue;
607
608 if (!strcmp(props->name, "EDID")) {
609 if (drmmode_output->edid_blob)
610 drmModeFreePropertyBlob(drmmode_output->edid_blob);
611 drmmode_output->edid_blob =
Rob Clark74210d52012-01-08 17:59:08 -0600612 drmModeGetPropertyBlob(drmmode->fd,
613 koutput->prop_values[i]);
Rob Clark487687e2011-07-17 17:29:02 -0500614 }
615 drmModeFreeProperty(props);
616 }
617
618 if (drmmode_output->edid_blob)
619 ddc_mon = xf86InterpretEDID(pScrn->scrnIndex,
Rob Clark74210d52012-01-08 17:59:08 -0600620 drmmode_output->edid_blob->data);
Rob Clark487687e2011-07-17 17:29:02 -0500621
622 if (ddc_mon) {
Rob Clark74210d52012-01-08 17:59:08 -0600623 XF86_CRTC_CONFIG_PTR(pScrn)->debug_modes = TRUE;
Rob Clark487687e2011-07-17 17:29:02 -0500624 xf86PrintEDID(ddc_mon);
625 xf86OutputSetEDID(output, ddc_mon);
626 xf86SetDDCproperties(pScrn, ddc_mon);
627 }
628
629 DEBUG_MSG("count_modes: %d", koutput->count_modes);
630
631 /* modes should already be available */
632 for (i = 0; i < koutput->count_modes; i++) {
633 Mode = xnfalloc(sizeof(DisplayModeRec));
634
635 drmmode_ConvertFromKMode(pScrn, &koutput->modes[i],
Rob Clark74210d52012-01-08 17:59:08 -0600636 Mode);
Rob Clark487687e2011-07-17 17:29:02 -0500637 Modes = xf86ModesAdd(Modes, Mode);
638
639 }
640 return Modes;
641}
642
643static void
644drmmode_output_destroy(xf86OutputPtr output)
645{
646 drmmode_output_private_ptr drmmode_output = output->driver_private;
647 int i;
648
649 if (drmmode_output->edid_blob)
650 drmModeFreePropertyBlob(drmmode_output->edid_blob);
651 for (i = 0; i < drmmode_output->num_props; i++) {
652 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
653 free(drmmode_output->props[i].atoms);
654 }
655 drmModeFreeConnector(drmmode_output->mode_output);
656 free(drmmode_output);
657 output->driver_private = NULL;
658}
659
660static void
661drmmode_output_dpms(xf86OutputPtr output, int mode)
662{
663 drmmode_output_private_ptr drmmode_output = output->driver_private;
664 drmModeConnectorPtr koutput = drmmode_output->mode_output;
665 drmModePropertyPtr props;
666 drmmode_ptr drmmode = drmmode_output->drmmode;
667 int mode_id = -1, i;
668
669 for (i = 0; i < koutput->count_props; i++) {
670 props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
671 if (props && (props->flags && DRM_MODE_PROP_ENUM)) {
672 if (!strcmp(props->name, "DPMS")) {
673 mode_id = koutput->props[i];
674 drmModeFreeProperty(props);
675 break;
676 }
677 drmModeFreeProperty(props);
678 }
679 }
680
681 if (mode_id < 0)
682 return;
683
684 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
Rob Clark74210d52012-01-08 17:59:08 -0600685 mode_id, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500686}
687
688static Bool
689drmmode_property_ignore(drmModePropertyPtr prop)
690{
691 if (!prop)
Rob Clark74210d52012-01-08 17:59:08 -0600692 return TRUE;
Rob Clark487687e2011-07-17 17:29:02 -0500693 /* ignore blob prop */
694 if (prop->flags & DRM_MODE_PROP_BLOB)
695 return TRUE;
696 /* ignore standard property */
697 if (!strcmp(prop->name, "EDID") ||
Rob Clark74210d52012-01-08 17:59:08 -0600698 !strcmp(prop->name, "DPMS"))
Rob Clark487687e2011-07-17 17:29:02 -0500699 return TRUE;
700
701 return FALSE;
702}
703
704static void
705drmmode_output_create_resources(xf86OutputPtr output)
706{
707 drmmode_output_private_ptr drmmode_output = output->driver_private;
708 drmModeConnectorPtr mode_output = drmmode_output->mode_output;
709 drmmode_ptr drmmode = drmmode_output->drmmode;
710 drmModePropertyPtr drmmode_prop;
711 uint32_t value;
712 int i, j, err;
713
714 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
715 if (!drmmode_output->props)
716 return;
717
718 drmmode_output->num_props = 0;
719 for (i = 0, j = 0; i < mode_output->count_props; i++) {
720 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
721 if (drmmode_property_ignore(drmmode_prop)) {
722 drmModeFreeProperty(drmmode_prop);
723 continue;
724 }
725 drmmode_output->props[j].mode_prop = drmmode_prop;
726 drmmode_output->props[j].index = i;
727 drmmode_output->num_props++;
728 j++;
729 }
730
731 for (i = 0; i < drmmode_output->num_props; i++) {
732 drmmode_prop_ptr p = &drmmode_output->props[i];
733 drmmode_prop = p->mode_prop;
734
735 value = drmmode_output->mode_output->prop_values[p->index];
736
737 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
738 INT32 range[2];
739
740 p->num_atoms = 1;
741 p->atoms = calloc(p->num_atoms, sizeof(Atom));
742 if (!p->atoms)
743 continue;
744 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
745 range[0] = drmmode_prop->values[0];
746 range[1] = drmmode_prop->values[1];
747 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600748 FALSE, TRUE,
749 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
Rob Clark487687e2011-07-17 17:29:02 -0500750 2, range);
751 if (err != 0) {
752 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600753 "RRConfigureOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500754 }
755 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600756 XA_INTEGER, 32, PropModeReplace, 1,
757 &value, FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500758 if (err != 0) {
759 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600760 "RRChangeOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500761 }
762 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
763 p->num_atoms = drmmode_prop->count_enums + 1;
764 p->atoms = calloc(p->num_atoms, sizeof(Atom));
765 if (!p->atoms)
766 continue;
767 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
768 for (j = 1; j <= drmmode_prop->count_enums; j++) {
769 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
770 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
771 }
772 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600773 FALSE, FALSE,
774 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
Rob Clark487687e2011-07-17 17:29:02 -0500775 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
776 if (err != 0) {
777 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600778 "RRConfigureOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500779 }
780 for (j = 0; j < drmmode_prop->count_enums; j++)
781 if (drmmode_prop->enums[j].value == value)
782 break;
783 /* there's always a matching value */
784 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600785 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500786 if (err != 0) {
787 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600788 "RRChangeOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500789 }
790 }
791 }
792}
793
794static Bool
795drmmode_output_set_property(xf86OutputPtr output, Atom property,
Rob Clark74210d52012-01-08 17:59:08 -0600796 RRPropertyValuePtr value)
Rob Clark487687e2011-07-17 17:29:02 -0500797{
798 drmmode_output_private_ptr drmmode_output = output->driver_private;
799 drmmode_ptr drmmode = drmmode_output->drmmode;
800 int i, ret;
801
802 for (i = 0; i < drmmode_output->num_props; i++) {
803 drmmode_prop_ptr p = &drmmode_output->props[i];
804
805 if (p->atoms[0] != property)
806 continue;
807
808 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
809 uint32_t val;
810
811 if (value->type != XA_INTEGER || value->format != 32 ||
Rob Clark74210d52012-01-08 17:59:08 -0600812 value->size != 1)
Rob Clark487687e2011-07-17 17:29:02 -0500813 return FALSE;
814 val = *(uint32_t *)value->data;
815
816 ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
Rob Clark74210d52012-01-08 17:59:08 -0600817 p->mode_prop->prop_id, (uint64_t)val);
Rob Clark487687e2011-07-17 17:29:02 -0500818
819 if (ret)
820 return FALSE;
821
822 return TRUE;
823
824 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
825 Atom atom;
826 const char *name;
827 int j;
828
829 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
830 return FALSE;
831 memcpy(&atom, value->data, 4);
832 name = NameForAtom(atom);
833
834 /* search for matching name string, then set its value down */
835 for (j = 0; j < p->mode_prop->count_enums; j++) {
836 if (!strcmp(p->mode_prop->enums[j].name, name)) {
837 ret = drmModeConnectorSetProperty(drmmode->fd,
Rob Clark74210d52012-01-08 17:59:08 -0600838 drmmode_output->output_id,
839 p->mode_prop->prop_id,
840 p->mode_prop->enums[j].value);
Rob Clark487687e2011-07-17 17:29:02 -0500841
842 if (ret)
843 return FALSE;
844
845 return TRUE;
846 }
847 }
848
849 return FALSE;
850 }
851 }
852
853 return TRUE;
854}
855
856static Bool
857drmmode_output_get_property(xf86OutputPtr output, Atom property)
858{
859
860 drmmode_output_private_ptr drmmode_output = output->driver_private;
861 drmmode_ptr drmmode = drmmode_output->drmmode;
862 uint32_t value;
863 int err, i;
864
865 if (output->scrn->vtSema) {
866 drmModeFreeConnector(drmmode_output->mode_output);
867 drmmode_output->mode_output =
Rob Clark74210d52012-01-08 17:59:08 -0600868 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500869 }
870
871 for (i = 0; i < drmmode_output->num_props; i++) {
872 drmmode_prop_ptr p = &drmmode_output->props[i];
873 if (p->atoms[0] != property)
874 continue;
875
876 value = drmmode_output->mode_output->prop_values[p->index];
877
878 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
879 err = RRChangeOutputProperty(output->randr_output,
Rob Clark74210d52012-01-08 17:59:08 -0600880 property, XA_INTEGER, 32,
881 PropModeReplace, 1, &value,
882 FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500883
884 return !err;
885 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
886 int j;
887
888 /* search for matching name string, then set its value down */
889 for (j = 0; j < p->mode_prop->count_enums; j++) {
890 if (p->mode_prop->enums[j].value == value)
891 break;
892 }
893
894 err = RRChangeOutputProperty(output->randr_output, property,
Rob Clark74210d52012-01-08 17:59:08 -0600895 XA_ATOM, 32, PropModeReplace, 1,
896 &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500897
898 return !err;
899 }
900 }
901
902 return FALSE;
903}
904
905static const xf86OutputFuncsRec drmmode_output_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600906 .create_resources = drmmode_output_create_resources,
907 .dpms = drmmode_output_dpms,
908 .detect = drmmode_output_detect,
909 .mode_valid = drmmode_output_mode_valid,
910 .get_modes = drmmode_output_get_modes,
911 .set_property = drmmode_output_set_property,
912 .get_property = drmmode_output_get_property,
913 .destroy = drmmode_output_destroy
Rob Clark487687e2011-07-17 17:29:02 -0500914};
915
916// FIXME - Eliminate the following values that aren't accurate for OMAP4:
917const char *output_names[] = { "None",
Rob Clark74210d52012-01-08 17:59:08 -0600918 "VGA",
919 "DVI-I",
920 "DVI-D",
921 "DVI-A",
922 "Composite",
923 "SVIDEO",
924 "LVDS",
925 "CTV",
926 "DIN",
927 "DP",
928 "HDMI",
929 "HDMI",
930 "TV",
931 "eDP",
Rob Clark487687e2011-07-17 17:29:02 -0500932};
933#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
934
935static void
936drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
937{
Rob Clark74210d52012-01-08 17:59:08 -0600938 xf86OutputPtr output;
939 drmModeConnectorPtr koutput;
940 drmModeEncoderPtr kencoder;
941 drmmode_output_private_ptr drmmode_output;
942 char name[32];
Rob Clark487687e2011-07-17 17:29:02 -0500943
Rob Clark74210d52012-01-08 17:59:08 -0600944 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -0500945
Rob Clark74210d52012-01-08 17:59:08 -0600946 koutput = drmModeGetConnector(drmmode->fd,
947 drmmode->mode_res->connectors[num]);
948 if (!koutput)
949 return;
Rob Clark487687e2011-07-17 17:29:02 -0500950
Rob Clark74210d52012-01-08 17:59:08 -0600951 kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
952 if (!kencoder) {
953 drmModeFreeConnector(koutput);
954 return;
955 }
Rob Clark487687e2011-07-17 17:29:02 -0500956
Rob Clark74210d52012-01-08 17:59:08 -0600957 if (koutput->connector_type >= NUM_OUTPUT_NAMES)
958 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
959 koutput->connector_type_id);
960 else
961 snprintf(name, 32, "%s-%d",
962 output_names[koutput->connector_type],
963 koutput->connector_type_id);
Rob Clark487687e2011-07-17 17:29:02 -0500964
Rob Clark74210d52012-01-08 17:59:08 -0600965 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
966 if (!output) {
967 drmModeFreeEncoder(kencoder);
968 drmModeFreeConnector(koutput);
969 return;
970 }
Rob Clark487687e2011-07-17 17:29:02 -0500971
Rob Clark74210d52012-01-08 17:59:08 -0600972 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
973 if (!drmmode_output) {
974 xf86OutputDestroy(output);
975 drmModeFreeConnector(koutput);
976 drmModeFreeEncoder(kencoder);
977 return;
978 }
Rob Clark487687e2011-07-17 17:29:02 -0500979
Rob Clark74210d52012-01-08 17:59:08 -0600980 drmmode_output->output_id = drmmode->mode_res->connectors[num];
981 drmmode_output->mode_output = koutput;
982 drmmode_output->mode_encoder = kencoder;
983 drmmode_output->drmmode = drmmode;
Rob Clark487687e2011-07-17 17:29:02 -0500984
Rob Clark74210d52012-01-08 17:59:08 -0600985 output->mm_width = koutput->mmWidth;
986 output->mm_height = koutput->mmHeight;
987 output->driver_private = drmmode_output;
Rob Clark487687e2011-07-17 17:29:02 -0500988
Rob Clark74210d52012-01-08 17:59:08 -0600989 output->possible_crtcs = kencoder->possible_crtcs;
990 output->possible_clones = kencoder->possible_clones;
991 output->interlaceAllowed = TRUE;
Rob Clark487687e2011-07-17 17:29:02 -0500992
Rob Clark74210d52012-01-08 17:59:08 -0600993 TRACE_EXIT();
994 return;
995}
Rob Clark487687e2011-07-17 17:29:02 -0500996
David Garbett3688b332012-05-11 12:17:34 +0100997void set_scanout_bo(ScrnInfoPtr pScrn, struct omap_bo *bo)
998{
999 OMAPPtr pOMAP = OMAPPTR(pScrn);
1000
1001 /* It had better have a framebuffer if we're scanning it out */
1002 assert(omap_bo_get_fb(bo));
1003
1004 pOMAP->scanout = bo;
1005}
1006
Rob Clark487687e2011-07-17 17:29:02 -05001007static Bool
1008drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
1009{
1010 OMAPPtr pOMAP = OMAPPTR(pScrn);
1011 ScreenPtr pScreen = pScrn->pScreen;
1012 unsigned int pitch;
David Garbett3688b332012-05-11 12:17:34 +01001013 struct omap_bo *new_scanout;
1014 int res;
1015 uint32_t new_fb_id;
1016 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001017
1018 TRACE_ENTER();
1019
1020 /* if fb required size has changed, realloc! */
1021
1022 DEBUG_MSG("Resize! %dx%d", width, height);
1023
1024 pScrn->virtualX = width;
1025 pScrn->virtualY = height;
1026
1027 pitch = OMAPCalculateStride(width, pScrn->bitsPerPixel);
1028
1029 if ((pitch * height) != omap_bo_size(pOMAP->scanout)) {
1030 /* hmm, should we remove fb here.. we don't want to keep
1031 * scanning out a deallocated buffer..
1032 */
1033 drmmode_remove_fb(pScrn);
1034
1035 /* delete old scanout buffer */
1036 omap_bo_del(pOMAP->scanout);
1037
1038 DEBUG_MSG("allocating new scanout buffer: %dx%d (%d)",
1039 width, height, pitch);
1040
1041 /* allocate new scanout buffer */
David Garbett3688b332012-05-11 12:17:34 +01001042 new_scanout = omap_bo_new(pOMAP->dev, height * pitch,
Rob Clark487687e2011-07-17 17:29:02 -05001043 OMAP_BO_SCANOUT | OMAP_BO_WC);
David Garbett3688b332012-05-11 12:17:34 +01001044
1045 if (!new_scanout) {
Rob Clark487687e2011-07-17 17:29:02 -05001046 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1047 "Error reallocating scanout buffer\n");
1048 return FALSE;
1049 }
David Garbett3688b332012-05-11 12:17:34 +01001050
1051 res = drmModeAddFB(drmmode->fd,
1052 width, height,
1053 pScrn->depth, pScrn->bitsPerPixel,
1054 pitch, omap_bo_handle(new_scanout),
1055 &new_fb_id);
1056 if (res < 0) {
1057 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1058 "Error adding fb for scanout buffer\n");
1059 return FALSE;
1060 }
1061
1062 omap_bo_set_fb(new_scanout, new_fb_id);
1063
1064 set_scanout_bo(pScrn, new_scanout);
1065
1066 pScrn->displayWidth = pitch / (pScrn->bitsPerPixel / 8);
Rob Clark487687e2011-07-17 17:29:02 -05001067 }
1068
1069 if (pScreen && pScreen->ModifyPixmapHeader) {
1070 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1071 pScreen->ModifyPixmapHeader(rootPixmap,
1072 pScrn->virtualX, pScrn->virtualY,
1073 pScrn->depth, pScrn->bitsPerPixel, pitch,
1074 omap_bo_map(pOMAP->scanout));
1075 }
1076
1077 TRACE_EXIT();
1078 return TRUE;
Rob Clark74210d52012-01-08 17:59:08 -06001079}
Rob Clark487687e2011-07-17 17:29:02 -05001080
1081static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -06001082 drmmode_xf86crtc_resize
Rob Clark487687e2011-07-17 17:29:02 -05001083};
1084
1085
1086Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
1087{
Rob Clark74210d52012-01-08 17:59:08 -06001088 drmmode_ptr drmmode;
1089 int i;
Rob Clark487687e2011-07-17 17:29:02 -05001090
Rob Clark74210d52012-01-08 17:59:08 -06001091 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001092
Rob Clark74210d52012-01-08 17:59:08 -06001093 drmmode = calloc(1, sizeof *drmmode);
1094 drmmode->fd = fd;
Rob Clark487687e2011-07-17 17:29:02 -05001095
Rob Clark74210d52012-01-08 17:59:08 -06001096 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
Rob Clark487687e2011-07-17 17:29:02 -05001097
1098
Rob Clark74210d52012-01-08 17:59:08 -06001099 drmmode->cpp = cpp;
1100 drmmode->mode_res = drmModeGetResources(drmmode->fd);
1101 if (!drmmode->mode_res) {
1102 return FALSE;
1103 } else {
1104 DEBUG_MSG("Got KMS resources");
1105 DEBUG_MSG(" %d connectors, %d encoders",
1106 drmmode->mode_res->count_connectors,
1107 drmmode->mode_res->count_encoders);
1108 DEBUG_MSG(" %d crtcs, %d fbs",
1109 drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs);
1110 DEBUG_MSG(" %dx%d minimum resolution",
1111 drmmode->mode_res->min_width, drmmode->mode_res->min_height);
1112 DEBUG_MSG(" %dx%d maximum resolution",
1113 drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1114 }
1115 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
1116 drmmode->mode_res->max_height);
1117 for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1118 drmmode_crtc_init(pScrn, drmmode, i);
Rob Clark487687e2011-07-17 17:29:02 -05001119
Rob Clark74210d52012-01-08 17:59:08 -06001120 for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1121 drmmode_output_init(pScrn, drmmode, i);
Rob Clark487687e2011-07-17 17:29:02 -05001122
Rob Clark74210d52012-01-08 17:59:08 -06001123 xf86InitialConfiguration(pScrn, TRUE);
Rob Clark487687e2011-07-17 17:29:02 -05001124
Rob Clark74210d52012-01-08 17:59:08 -06001125 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -05001126
Rob Clark74210d52012-01-08 17:59:08 -06001127 return TRUE;
1128}
Rob Clark487687e2011-07-17 17:29:02 -05001129
1130void
1131drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y, int flags)
1132{
1133 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1134 xf86OutputPtr output = config->output[config->compat_output];
1135 xf86CrtcPtr crtc = output->crtc;
1136
1137 if (!crtc || !crtc->enabled)
1138 return;
1139
1140 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
1141}
1142
Rob Clark4b8f30a2011-08-28 12:51:26 -05001143/*
1144 * Page Flipping
1145 */
1146
1147static void
1148page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
Rob Clark74210d52012-01-08 17:59:08 -06001149 unsigned int tv_usec, void *user_data)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001150{
Rob Clark4b8f30a2011-08-28 12:51:26 -05001151 OMAPDRI2SwapComplete(user_data);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001152}
1153
1154static drmEventContext event_context = {
1155 .version = DRM_EVENT_CONTEXT_VERSION,
1156 .page_flip_handler = page_flip_handler,
1157};
1158
1159Bool
1160drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
1161{
1162 ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
1163 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1164 drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
1165 drmmode_ptr mode = crtc->drmmode;
1166 int ret, i;
1167
1168 /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
1169 for (i = 0; i < config->num_crtc; i++) {
1170 crtc = config->crtc[i]->driver_private;
1171
1172 if (!config->crtc[i]->enabled)
1173 continue;
1174
1175 ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
1176 fb_id, DRM_MODE_PAGE_FLIP_EVENT, priv);
1177 if (ret) {
1178 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
Rob Clark74210d52012-01-08 17:59:08 -06001179 "flip queue failed: %s\n", strerror(errno));
Rob Clark4b8f30a2011-08-28 12:51:26 -05001180 return FALSE;
1181 }
1182 }
1183
Raymond Smith64c840e2012-05-02 10:27:51 +01001184 /* TODO: This is a hack because the PL111 driver doesn't currently support
1185 * vblank counting, so page_flip_handler will never get called otherwise */
1186 page_flip_handler(0, 0, 0, 0, priv);
1187
Rob Clark4b8f30a2011-08-28 12:51:26 -05001188 return TRUE;
1189}
Rob Clark487687e2011-07-17 17:29:02 -05001190
1191/*
1192 * Hot Plug Event handling:
1193 */
1194
Rob Clark487687e2011-07-17 17:29:02 -05001195static void
1196drmmode_handle_uevents(int fd, void *closure)
1197{
Rob Clark74210d52012-01-08 17:59:08 -06001198 ScrnInfoPtr pScrn = closure;
1199 OMAPPtr pOMAP = OMAPPTR(pScrn);
1200 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1201 struct udev_device *dev;
1202 const char *hotplug;
1203 struct stat s;
1204 dev_t udev_devnum;
Rob Clark487687e2011-07-17 17:29:02 -05001205
Rob Clark74210d52012-01-08 17:59:08 -06001206 dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1207 if (!dev)
1208 return;
Rob Clark487687e2011-07-17 17:29:02 -05001209
Rob Clark74210d52012-01-08 17:59:08 -06001210 // FIXME - Do we need to keep this code, which Rob originally wrote
1211 // (i.e. up thru the "if" statement)?:
Rob Clark487687e2011-07-17 17:29:02 -05001212
Rob Clark74210d52012-01-08 17:59:08 -06001213 /*
1214 * Check to make sure this event is directed at our
1215 * device (by comparing dev_t values), then make
1216 * sure it's a hotplug event (HOTPLUG=1)
1217 */
1218 udev_devnum = udev_device_get_devnum(dev);
1219 fstat(pOMAP->drmFD, &s);
Rob Clark487687e2011-07-17 17:29:02 -05001220
Rob Clark74210d52012-01-08 17:59:08 -06001221 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
Rob Clark487687e2011-07-17 17:29:02 -05001222
Rob Clark74210d52012-01-08 17:59:08 -06001223 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug,
1224 memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)));
Rob Clark487687e2011-07-17 17:29:02 -05001225
Rob Clark74210d52012-01-08 17:59:08 -06001226 if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
1227 hotplug && atoi(hotplug) == 1) {
1228 RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE);
1229 }
1230 udev_device_unref(dev);
1231}
Rob Clark487687e2011-07-17 17:29:02 -05001232
Rob Clark4b8f30a2011-08-28 12:51:26 -05001233static void
Rob Clark487687e2011-07-17 17:29:02 -05001234drmmode_uevent_init(ScrnInfoPtr pScrn)
1235{
Rob Clark74210d52012-01-08 17:59:08 -06001236 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1237 struct udev *u;
1238 struct udev_monitor *mon;
Rob Clark487687e2011-07-17 17:29:02 -05001239
Rob Clark74210d52012-01-08 17:59:08 -06001240 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001241
Rob Clark74210d52012-01-08 17:59:08 -06001242 u = udev_new();
1243 if (!u)
1244 return;
1245 mon = udev_monitor_new_from_netlink(u, "udev");
1246 if (!mon) {
1247 udev_unref(u);
1248 return;
1249 }
Rob Clark487687e2011-07-17 17:29:02 -05001250
Rob Clark74210d52012-01-08 17:59:08 -06001251 if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1252 "drm",
1253 "drm_minor") < 0 ||
1254 udev_monitor_enable_receiving(mon) < 0) {
1255 udev_monitor_unref(mon);
1256 udev_unref(u);
1257 return;
1258 }
Rob Clark487687e2011-07-17 17:29:02 -05001259
Rob Clark74210d52012-01-08 17:59:08 -06001260 drmmode->uevent_handler =
1261 xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1262 drmmode_handle_uevents, pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001263
Rob Clark74210d52012-01-08 17:59:08 -06001264 drmmode->uevent_monitor = mon;
Rob Clark487687e2011-07-17 17:29:02 -05001265
Rob Clark74210d52012-01-08 17:59:08 -06001266 TRACE_EXIT();
1267}
Rob Clark487687e2011-07-17 17:29:02 -05001268
Rob Clark4b8f30a2011-08-28 12:51:26 -05001269static void
Rob Clark487687e2011-07-17 17:29:02 -05001270drmmode_uevent_fini(ScrnInfoPtr pScrn)
1271{
Rob Clark74210d52012-01-08 17:59:08 -06001272 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001273
Rob Clark74210d52012-01-08 17:59:08 -06001274 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001275
Rob Clark74210d52012-01-08 17:59:08 -06001276 if (drmmode->uevent_handler) {
1277 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1278 xf86RemoveGeneralHandler(drmmode->uevent_handler);
Rob Clark487687e2011-07-17 17:29:02 -05001279
Rob Clark74210d52012-01-08 17:59:08 -06001280 udev_monitor_unref(drmmode->uevent_monitor);
1281 udev_unref(u);
1282 }
Rob Clark487687e2011-07-17 17:29:02 -05001283
Rob Clark74210d52012-01-08 17:59:08 -06001284 TRACE_EXIT();
1285}
Rob Clark4b8f30a2011-08-28 12:51:26 -05001286
1287static void
1288drmmode_wakeup_handler(pointer data, int err, pointer p)
1289{
Rob Clark67b875f2012-04-20 19:13:57 -05001290 ScrnInfoPtr pScrn = data;
1291 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001292 fd_set *read_mask = p;
1293
Rob Clark67b875f2012-04-20 19:13:57 -05001294 if (pScrn == NULL || err < 0)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001295 return;
1296
1297 if (FD_ISSET(drmmode->fd, read_mask))
1298 drmHandleEvent(drmmode->fd, &event_context);
1299}
1300
1301void
Rob Clark67b875f2012-04-20 19:13:57 -05001302drmmode_wait_for_event(ScrnInfoPtr pScrn)
1303{
1304 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1305 drmHandleEvent(drmmode->fd, &event_context);
1306}
1307
1308void
Rob Clark4b8f30a2011-08-28 12:51:26 -05001309drmmode_screen_init(ScrnInfoPtr pScrn)
1310{
Rob Clark74210d52012-01-08 17:59:08 -06001311 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001312
1313 drmmode_uevent_init(pScrn);
1314
Rob Clark74210d52012-01-08 17:59:08 -06001315 AddGeneralSocket(drmmode->fd);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001316
Rob Clark74210d52012-01-08 17:59:08 -06001317 /* Register a wakeup handler to get informed on DRM events */
1318 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1319 drmmode_wakeup_handler, pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001320}
1321
1322void
1323drmmode_screen_fini(ScrnInfoPtr pScrn)
1324{
1325 drmmode_uevent_fini(pScrn);
1326}