blob: f2b2acd7894449c4c618500f124b07d4f073934b [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
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;
Rob Clark687c6082012-01-08 19:33:18 -0600103} drmmode_cursor_rec, *drmmode_cursor_ptr;
104
105typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600106 int fd;
Rob Clark74210d52012-01-08 17:59:08 -0600107 drmModeResPtr mode_res;
108 int cpp;
109 struct udev_monitor *uevent_monitor;
110 InputHandlerProc uevent_handler;
Rob Clark687c6082012-01-08 19:33:18 -0600111 drmmode_cursor_ptr cursor;
Rob Clark487687e2011-07-17 17:29:02 -0500112} drmmode_rec, *drmmode_ptr;
113
114typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600115 drmmode_ptr drmmode;
116 drmModeCrtcPtr mode_crtc;
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700117 int cursor_visible;
Rob Clark487687e2011-07-17 17:29:02 -0500118} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
119
120typedef struct {
121 drmModePropertyPtr mode_prop;
122 int index; /* Index within the kernel-side property arrays for
Rob Clark74210d52012-01-08 17:59:08 -0600123 * this connector. */
Rob Clark487687e2011-07-17 17:29:02 -0500124 int num_atoms; /* if range prop, num_atoms == 1; if enum prop,
Rob Clark74210d52012-01-08 17:59:08 -0600125 * num_atoms == num_enums + 1 */
Rob Clark487687e2011-07-17 17:29:02 -0500126 Atom *atoms;
127} drmmode_prop_rec, *drmmode_prop_ptr;
128
129typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600130 drmmode_ptr drmmode;
131 int output_id;
132 drmModeConnectorPtr mode_output;
133 drmModeEncoderPtr mode_encoder;
134 drmModePropertyBlobPtr edid_blob;
135 int num_props;
136 drmmode_prop_ptr props;
Rob Clark487687e2011-07-17 17:29:02 -0500137} drmmode_output_private_rec, *drmmode_output_private_ptr;
138
139static void drmmode_output_dpms(xf86OutputPtr output, int mode);
Rob Clark487687e2011-07-17 17:29:02 -0500140
Rob Clark687c6082012-01-08 19:33:18 -0600141static drmmode_ptr
142drmmode_from_scrn(ScrnInfoPtr pScrn)
143{
144 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
145 drmmode_crtc_private_ptr drmmode_crtc;
146
147 drmmode_crtc = xf86_config->crtc[0]->driver_private;
148 return drmmode_crtc->drmmode;
149}
150
Rob Clark487687e2011-07-17 17:29:02 -0500151static void
152drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600153 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500154{
Rob Clark74210d52012-01-08 17:59:08 -0600155 memset(mode, 0, sizeof(DisplayModeRec));
156 mode->status = MODE_OK;
Rob Clark487687e2011-07-17 17:29:02 -0500157
Rob Clark74210d52012-01-08 17:59:08 -0600158 mode->Clock = kmode->clock;
Rob Clark487687e2011-07-17 17:29:02 -0500159
Rob Clark74210d52012-01-08 17:59:08 -0600160 mode->HDisplay = kmode->hdisplay;
161 mode->HSyncStart = kmode->hsync_start;
162 mode->HSyncEnd = kmode->hsync_end;
163 mode->HTotal = kmode->htotal;
164 mode->HSkew = kmode->hskew;
Rob Clark487687e2011-07-17 17:29:02 -0500165
Rob Clark74210d52012-01-08 17:59:08 -0600166 mode->VDisplay = kmode->vdisplay;
167 mode->VSyncStart = kmode->vsync_start;
168 mode->VSyncEnd = kmode->vsync_end;
169 mode->VTotal = kmode->vtotal;
170 mode->VScan = kmode->vscan;
Rob Clark487687e2011-07-17 17:29:02 -0500171
Rob Clark74210d52012-01-08 17:59:08 -0600172 mode->Flags = kmode->flags; //& FLAG_BITS;
173 mode->name = strdup(kmode->name);
Rob Clark487687e2011-07-17 17:29:02 -0500174
Rob Clark74210d52012-01-08 17:59:08 -0600175 DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500176
Rob Clark74210d52012-01-08 17:59:08 -0600177 if (kmode->type & DRM_MODE_TYPE_DRIVER)
178 mode->type = M_T_DRIVER;
179 if (kmode->type & DRM_MODE_TYPE_PREFERRED)
180 mode->type |= M_T_PREFERRED;
Rob Clark487687e2011-07-17 17:29:02 -0500181
Rob Clark74210d52012-01-08 17:59:08 -0600182 xf86SetModeCrtc (mode, pScrn->adjustFlags);
183}
Rob Clark487687e2011-07-17 17:29:02 -0500184
185static void
186drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600187 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500188{
Rob Clark74210d52012-01-08 17:59:08 -0600189 memset(kmode, 0, sizeof(*kmode));
Rob Clark487687e2011-07-17 17:29:02 -0500190
Rob Clark74210d52012-01-08 17:59:08 -0600191 kmode->clock = mode->Clock;
192 kmode->hdisplay = mode->HDisplay;
193 kmode->hsync_start = mode->HSyncStart;
194 kmode->hsync_end = mode->HSyncEnd;
195 kmode->htotal = mode->HTotal;
196 kmode->hskew = mode->HSkew;
Rob Clark487687e2011-07-17 17:29:02 -0500197
Rob Clark74210d52012-01-08 17:59:08 -0600198 kmode->vdisplay = mode->VDisplay;
199 kmode->vsync_start = mode->VSyncStart;
200 kmode->vsync_end = mode->VSyncEnd;
201 kmode->vtotal = mode->VTotal;
202 kmode->vscan = mode->VScan;
Rob Clark487687e2011-07-17 17:29:02 -0500203
Rob Clark74210d52012-01-08 17:59:08 -0600204 kmode->flags = mode->Flags; //& FLAG_BITS;
205 if (mode->name)
206 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
207 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
208}
Rob Clark487687e2011-07-17 17:29:02 -0500209
210static void
211drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
212{
Rob Clark74210d52012-01-08 17:59:08 -0600213 // FIXME - Implement this function
214}
Rob Clark487687e2011-07-17 17:29:02 -0500215
216static Bool
217drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rob Clark74210d52012-01-08 17:59:08 -0600218 Rotation rotation, int x, int y)
Rob Clark487687e2011-07-17 17:29:02 -0500219{
220 ScrnInfoPtr pScrn = crtc->scrn;
221 OMAPPtr pOMAP = OMAPPTR(pScrn);
222 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
223 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
224 drmmode_ptr drmmode = drmmode_crtc->drmmode;
225 int saved_x, saved_y;
226 Rotation saved_rotation;
227 DisplayModeRec saved_mode;
228 uint32_t *output_ids = NULL;
229 int output_count = 0;
230 int ret = TRUE;
231 int i;
David Garbett7171c522012-05-11 13:12:50 +0100232 uint32_t fb_id;
Rob Clark487687e2011-07-17 17:29:02 -0500233 drmModeModeInfo kmode;
234
235 TRACE_ENTER();
236
David Garbett7171c522012-05-11 13:12:50 +0100237 fb_id = omap_bo_get_fb(pOMAP->scanout);
238
239 if (fb_id == 0) {
David Garbett7171c522012-05-11 13:12:50 +0100240
241 DEBUG_MSG("create framebuffer: %dx%d",
242 pScrn->virtualX, pScrn->virtualY);
243
Sean Paul3e107302012-08-30 12:08:12 -0700244 ret = omap_bo_add_fb(pOMAP->scanout);
245 if (ret)
David Garbett7171c522012-05-11 13:12:50 +0100246 return FALSE;
David Garbett7171c522012-05-11 13:12:50 +0100247 }
Rob Clark487687e2011-07-17 17:29:02 -0500248
249 /* Save the current mode in case there's a problem: */
250 saved_mode = crtc->mode;
251 saved_x = crtc->x;
252 saved_y = crtc->y;
253 saved_rotation = crtc->rotation;
254
255 /* Set the new mode: */
256 crtc->mode = *mode;
257 crtc->x = x;
258 crtc->y = y;
259 crtc->rotation = rotation;
260
261 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
262 if (!output_ids) {
263 // Fixme - have an error message?
264 ret = FALSE;
265 goto done;
266 }
267
268 for (i = 0; i < xf86_config->num_output; i++) {
269 xf86OutputPtr output = xf86_config->output[i];
270 drmmode_output_private_ptr drmmode_output;
271
272 if (output->crtc != crtc)
273 continue;
274
275 drmmode_output = output->driver_private;
276 output_ids[output_count] =
277 drmmode_output->mode_output->connector_id;
278 output_count++;
279 }
280
281 if (!xf86CrtcRotate(crtc))
282 goto done;
283
284 // Fixme - Intel puts this function here, and Nouveau puts it at the end
285 // of this function -> determine what's best for TI'S OMAP4:
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200286 if (crtc->funcs->gamma_set)
287 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
288 crtc->gamma_blue, crtc->gamma_size);
Rob Clark487687e2011-07-17 17:29:02 -0500289
290 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
291
Rob Clark487687e2011-07-17 17:29:02 -0500292 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
293 fb_id, x, y, output_ids, output_count, &kmode);
294 if (ret) {
295 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
296 "failed to set mode: %s\n", strerror(-ret));
297 } else {
298 ret = TRUE;
299 }
300
301 // FIXME - DO WE NEED TO CALL TO THE PVR EXA/DRI2 CODE TO UPDATE THEM???
302
303 /* Turn on any outputs on this crtc that may have been disabled: */
304 for (i = 0; i < xf86_config->num_output; i++) {
305 xf86OutputPtr output = xf86_config->output[i];
306
307 if (output->crtc != crtc)
308 continue;
309
310 drmmode_output_dpms(output, DPMSModeOn);
311 }
312
Rob Clark74210d52012-01-08 17:59:08 -0600313 // TODO: only call this if we are not using sw cursor.. ie. bad to call this
314 // if we haven't called xf86InitCursor()!!
315 // if (pScrn->pScreen)
316 // xf86_reload_cursors(pScrn->pScreen);
Rob Clark487687e2011-07-17 17:29:02 -0500317
318done:
319 if (output_ids) {
320 free(output_ids);
321 }
322 if (!ret) {
323 /* If there was a problem, resture the old mode: */
324 crtc->x = saved_x;
325 crtc->y = saved_y;
326 crtc->rotation = saved_rotation;
327 crtc->mode = saved_mode;
328 }
329
330 TRACE_EXIT();
331 return ret;
Rob Clark74210d52012-01-08 17:59:08 -0600332}
Rob Clark487687e2011-07-17 17:29:02 -0500333
Rob Clark60f5bad2012-01-22 18:35:28 -0600334#define CURSORW 64
335#define CURSORH 64
336
Rob Clark487687e2011-07-17 17:29:02 -0500337static void
Rob Clark487687e2011-07-17 17:29:02 -0500338drmmode_hide_cursor(xf86CrtcPtr crtc)
339{
Rob Clark74210d52012-01-08 17:59:08 -0600340 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
341 drmmode_ptr drmmode = drmmode_crtc->drmmode;
Rob Clark687c6082012-01-08 19:33:18 -0600342 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark487687e2011-07-17 17:29:02 -0500343
Rob Clark687c6082012-01-08 19:33:18 -0600344 if (!cursor)
345 return;
346
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700347 drmmode_crtc->cursor_visible = FALSE;
Rob Clark687c6082012-01-08 19:33:18 -0600348
349 /* set plane's fb_id to 0 to disable it */
350 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
351 drmmode_crtc->mode_crtc->crtc_id, 0, 0,
352 0, 0, 0, 0, 0, 0, 0, 0);
Rob Clark74210d52012-01-08 17:59:08 -0600353}
Rob Clark487687e2011-07-17 17:29:02 -0500354
355static void
356drmmode_show_cursor(xf86CrtcPtr crtc)
357{
Rob Clark74210d52012-01-08 17:59:08 -0600358 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
359 drmmode_ptr drmmode = drmmode_crtc->drmmode;
Rob Clark687c6082012-01-08 19:33:18 -0600360 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark60f5bad2012-01-22 18:35:28 -0600361 int crtc_x, crtc_y, src_x, src_y, w, h;
Rob Clark487687e2011-07-17 17:29:02 -0500362
Rob Clark687c6082012-01-08 19:33:18 -0600363 if (!cursor)
364 return;
Rob Clark487687e2011-07-17 17:29:02 -0500365
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700366 drmmode_crtc->cursor_visible = TRUE;
Rob Clark687c6082012-01-08 19:33:18 -0600367
Rob Clark60f5bad2012-01-22 18:35:28 -0600368 w = CURSORW;
369 h = CURSORH;
370 crtc_x = cursor->x;
371 crtc_y = cursor->y;
372 src_x = 0;
373 src_y = 0;
374
375 if (crtc_x < 0) {
376 src_x += -crtc_x;
377 w -= -crtc_x;
378 crtc_x = 0;
379 }
380
381 if (crtc_y < 0) {
382 src_y += -crtc_y;
383 h -= -crtc_y;
384 crtc_y = 0;
385 }
386
387 if ((crtc_x + w) > crtc->mode.HDisplay) {
388 w = crtc->mode.HDisplay - crtc_x;
389 }
390
391 if ((crtc_y + h) > crtc->mode.VDisplay) {
392 h = crtc->mode.VDisplay - crtc_y;
393 }
394
Rob Clark687c6082012-01-08 19:33:18 -0600395 /* note src coords (last 4 args) are in Q16 format */
396 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
397 drmmode_crtc->mode_crtc->crtc_id, cursor->fb_id, 0,
Rob Clark60f5bad2012-01-22 18:35:28 -0600398 crtc_x, crtc_y, w, h, src_x<<16, src_y<<16, w<<16, h<<16);
Rob Clark687c6082012-01-08 19:33:18 -0600399}
400
401static void
402drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
403{
404 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
405 drmmode_ptr drmmode = drmmode_crtc->drmmode;
406 drmmode_cursor_ptr cursor = drmmode->cursor;
407
408 if (!cursor)
409 return;
410
411 cursor->x = x;
412 cursor->y = y;
413
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700414 if (drmmode_crtc->cursor_visible)
Rob Clark687c6082012-01-08 19:33:18 -0600415 drmmode_show_cursor(crtc);
416}
417
418static void
419drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
420{
421 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
422 drmmode_ptr drmmode = drmmode_crtc->drmmode;
423 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark979add52012-02-21 18:35:24 -0600424 int visible;
Rob Clark687c6082012-01-08 19:33:18 -0600425
426 if (!cursor)
427 return;
428
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700429 visible = drmmode_crtc->cursor_visible;
Rob Clark979add52012-02-21 18:35:24 -0600430
431 if (visible)
Rob Clark687c6082012-01-08 19:33:18 -0600432 drmmode_hide_cursor(crtc);
433
434 memcpy(omap_bo_map(cursor->bo), image, omap_bo_size(cursor->bo));
435
Rob Clark979add52012-02-21 18:35:24 -0600436 if (visible)
Rob Clark687c6082012-01-08 19:33:18 -0600437 drmmode_show_cursor(crtc);
438}
439
440Bool
441drmmode_cursor_init(ScreenPtr pScreen)
442{
443 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
444 OMAPPtr pOMAP = OMAPPTR(pScrn);
445 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
446 drmmode_cursor_ptr cursor;
447 drmModePlaneRes *plane_resources;
448 drmModePlane *ovr;
449
450 /* technically we probably don't have any size limit.. since we
451 * are just using an overlay... but xserver will always create
452 * cursor images in the max size, so don't use width/height values
453 * that are too big
454 */
Rob Clark60f5bad2012-01-22 18:35:28 -0600455 int w = CURSORW, h = CURSORH;
Rob Clark687c6082012-01-08 19:33:18 -0600456 uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */
457
458 if (drmmode->cursor) {
459 INFO_MSG("cursor already initialized");
460 return TRUE;
461 }
462
463 cursor = calloc(1, sizeof(drmmode_cursor_rec));
464
465 /* find an unused plane which can be used as a mouse cursor. Note
466 * that we cheat a bit, in order to not burn one overlay per crtc,
467 * and only show the mouse cursor on one crtc at a time
468 */
469 plane_resources = drmModeGetPlaneResources(drmmode->fd);
470 if (!plane_resources) {
471 ERROR_MSG("drmModeGetPlaneResources failed: %s", strerror(errno));
472 return FALSE;
473 }
474
475 if (plane_resources->count_planes < 1) {
476 ERROR_MSG("not enough planes for HW cursor");
477 return FALSE;
478 }
479
480 ovr = drmModeGetPlane(drmmode->fd, plane_resources->planes[0]);
481 if (!ovr) {
482 ERROR_MSG("drmModeGetPlane failed: %s\n", strerror(errno));
483 return FALSE;
484 }
485
486 cursor->ovr = ovr;
Sean Paul3e107302012-08-30 12:08:12 -0700487 cursor->bo = omap_bo_new_with_dim(pOMAP->dev, w, h, 0, 32,
Rob Clark687c6082012-01-08 19:33:18 -0600488 OMAP_BO_SCANOUT | OMAP_BO_WC);
489
490 handles[0] = omap_bo_handle(cursor->bo);
David Garbettc5901532012-05-29 13:00:52 +0100491 pitches[0] = omap_bo_pitch(cursor->bo);
Rob Clark687c6082012-01-08 19:33:18 -0600492 offsets[0] = 0;
493
494 if (drmModeAddFB2(drmmode->fd, w, h, DRM_FORMAT_ARGB8888,
495 handles, pitches, offsets, &cursor->fb_id, 0)) {
496 ERROR_MSG("drmModeAddFB2 failed: %s", strerror(errno));
497 return FALSE;
498 }
499
500 if (xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) {
501 INFO_MSG("HW cursor initialized");
502 drmmode->cursor = cursor;
503 return TRUE;
504 }
505
506 // TODO cleanup when things fail..
507 return FALSE;
Rob Clark74210d52012-01-08 17:59:08 -0600508}
Rob Clark487687e2011-07-17 17:29:02 -0500509
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200510#if 1==OMAP_SUPPORT_GAMMA
Rob Clark487687e2011-07-17 17:29:02 -0500511static void
512drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
Rob Clark74210d52012-01-08 17:59:08 -0600513 int size)
Rob Clark487687e2011-07-17 17:29:02 -0500514{
515 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
516 drmmode_ptr drmmode = drmmode_crtc->drmmode;
517 int ret;
518
519 ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
Rob Clark74210d52012-01-08 17:59:08 -0600520 size, red, green, blue);
Rob Clark487687e2011-07-17 17:29:02 -0500521 if (ret != 0) {
522 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600523 "failed to set gamma: %s\n", strerror(-ret));
Rob Clark487687e2011-07-17 17:29:02 -0500524 }
525}
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200526#endif
Rob Clark487687e2011-07-17 17:29:02 -0500527
528static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600529 .dpms = drmmode_crtc_dpms,
530 .set_mode_major = drmmode_set_mode_major,
531 .set_cursor_position = drmmode_set_cursor_position,
532 .show_cursor = drmmode_show_cursor,
533 .hide_cursor = drmmode_hide_cursor,
534 .load_cursor_argb = drmmode_load_cursor_argb,
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200535#if 1==OMAP_SUPPORT_GAMMA
Rob Clark74210d52012-01-08 17:59:08 -0600536 .gamma_set = drmmode_gamma_set,
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200537#endif
Rob Clark487687e2011-07-17 17:29:02 -0500538};
539
540
541static void
542drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
543{
Rob Clark74210d52012-01-08 17:59:08 -0600544 xf86CrtcPtr crtc;
545 drmmode_crtc_private_ptr drmmode_crtc;
Rob Clark487687e2011-07-17 17:29:02 -0500546
Rob Clark74210d52012-01-08 17:59:08 -0600547 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -0500548
Rob Clark74210d52012-01-08 17:59:08 -0600549 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
550 if (crtc == NULL)
551 return;
552
553 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
554 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
555 drmmode->mode_res->crtcs[num]);
556 drmmode_crtc->drmmode = drmmode;
557
558 // FIXME - potentially add code to allocate a HW cursor here.
559
560 crtc->driver_private = drmmode_crtc;
561
562 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -0500563 return;
Rob Clark74210d52012-01-08 17:59:08 -0600564}
Rob Clark487687e2011-07-17 17:29:02 -0500565
566static xf86OutputStatus
567drmmode_output_detect(xf86OutputPtr output)
568{
569 /* go to the hw and retrieve a new output struct */
570 drmmode_output_private_ptr drmmode_output = output->driver_private;
571 drmmode_ptr drmmode = drmmode_output->drmmode;
572 xf86OutputStatus status;
573 drmModeFreeConnector(drmmode_output->mode_output);
574
575 drmmode_output->mode_output =
Rob Clark74210d52012-01-08 17:59:08 -0600576 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500577
578 switch (drmmode_output->mode_output->connection) {
579 case DRM_MODE_CONNECTED:
580 status = XF86OutputStatusConnected;
581 break;
582 case DRM_MODE_DISCONNECTED:
583 status = XF86OutputStatusDisconnected;
584 break;
585 default:
586 case DRM_MODE_UNKNOWNCONNECTION:
587 status = XF86OutputStatusUnknown;
588 break;
589 }
590 return status;
591}
592
593static Bool
594drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
595{
596 if (mode->type & M_T_DEFAULT)
597 /* Default modes are harmful here. */
598 return MODE_BAD;
599
600 return MODE_OK;
601}
602
603static DisplayModePtr
604drmmode_output_get_modes(xf86OutputPtr output)
605{
606 ScrnInfoPtr pScrn = output->scrn;
607 drmmode_output_private_ptr drmmode_output = output->driver_private;
608 drmModeConnectorPtr koutput = drmmode_output->mode_output;
609 drmmode_ptr drmmode = drmmode_output->drmmode;
610 DisplayModePtr Modes = NULL, Mode;
Daniel Kurtzb8131892012-10-17 01:39:54 +0800611 drmModePropertyPtr prop;
Rob Clark487687e2011-07-17 17:29:02 -0500612 xf86MonPtr ddc_mon = NULL;
613 int i;
614
615 /* look for an EDID property */
616 for (i = 0; i < koutput->count_props; i++) {
Daniel Kurtzb8131892012-10-17 01:39:54 +0800617 prop = drmModeGetProperty(drmmode->fd, koutput->props[i]);
618 if (!prop)
Rob Clark487687e2011-07-17 17:29:02 -0500619 continue;
620
Daniel Kurtzb8131892012-10-17 01:39:54 +0800621 if ((prop->flags & DRM_MODE_PROP_BLOB) &&
622 !strcmp(prop->name, "EDID")) {
Rob Clark487687e2011-07-17 17:29:02 -0500623 if (drmmode_output->edid_blob)
624 drmModeFreePropertyBlob(drmmode_output->edid_blob);
625 drmmode_output->edid_blob =
Rob Clark74210d52012-01-08 17:59:08 -0600626 drmModeGetPropertyBlob(drmmode->fd,
627 koutput->prop_values[i]);
Rob Clark487687e2011-07-17 17:29:02 -0500628 }
Daniel Kurtzb8131892012-10-17 01:39:54 +0800629 drmModeFreeProperty(prop);
Rob Clark487687e2011-07-17 17:29:02 -0500630 }
631
632 if (drmmode_output->edid_blob)
633 ddc_mon = xf86InterpretEDID(pScrn->scrnIndex,
Rob Clark74210d52012-01-08 17:59:08 -0600634 drmmode_output->edid_blob->data);
Rob Clark487687e2011-07-17 17:29:02 -0500635
636 if (ddc_mon) {
Rob Clark74210d52012-01-08 17:59:08 -0600637 XF86_CRTC_CONFIG_PTR(pScrn)->debug_modes = TRUE;
Rob Clark487687e2011-07-17 17:29:02 -0500638 xf86PrintEDID(ddc_mon);
639 xf86OutputSetEDID(output, ddc_mon);
640 xf86SetDDCproperties(pScrn, ddc_mon);
641 }
642
643 DEBUG_MSG("count_modes: %d", koutput->count_modes);
644
645 /* modes should already be available */
646 for (i = 0; i < koutput->count_modes; i++) {
647 Mode = xnfalloc(sizeof(DisplayModeRec));
648
649 drmmode_ConvertFromKMode(pScrn, &koutput->modes[i],
Rob Clark74210d52012-01-08 17:59:08 -0600650 Mode);
Rob Clark487687e2011-07-17 17:29:02 -0500651 Modes = xf86ModesAdd(Modes, Mode);
652
653 }
654 return Modes;
655}
656
657static void
658drmmode_output_destroy(xf86OutputPtr output)
659{
660 drmmode_output_private_ptr drmmode_output = output->driver_private;
661 int i;
662
663 if (drmmode_output->edid_blob)
664 drmModeFreePropertyBlob(drmmode_output->edid_blob);
665 for (i = 0; i < drmmode_output->num_props; i++) {
666 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
667 free(drmmode_output->props[i].atoms);
668 }
669 drmModeFreeConnector(drmmode_output->mode_output);
670 free(drmmode_output);
671 output->driver_private = NULL;
672}
673
674static void
675drmmode_output_dpms(xf86OutputPtr output, int mode)
676{
677 drmmode_output_private_ptr drmmode_output = output->driver_private;
678 drmModeConnectorPtr koutput = drmmode_output->mode_output;
Daniel Kurtzb8131892012-10-17 01:39:54 +0800679 drmModePropertyPtr prop;
Rob Clark487687e2011-07-17 17:29:02 -0500680 drmmode_ptr drmmode = drmmode_output->drmmode;
681 int mode_id = -1, i;
682
683 for (i = 0; i < koutput->count_props; i++) {
Daniel Kurtzb8131892012-10-17 01:39:54 +0800684 prop = drmModeGetProperty(drmmode->fd, koutput->props[i]);
685 if (!prop)
686 continue;
687 if ((prop->flags & DRM_MODE_PROP_ENUM) &&
688 !strcmp(prop->name, "DPMS")) {
689 mode_id = koutput->props[i];
690 drmModeFreeProperty(prop);
691 break;
Rob Clark487687e2011-07-17 17:29:02 -0500692 }
Daniel Kurtzb8131892012-10-17 01:39:54 +0800693 drmModeFreeProperty(prop);
Rob Clark487687e2011-07-17 17:29:02 -0500694 }
695
696 if (mode_id < 0)
697 return;
698
699 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
Rob Clark74210d52012-01-08 17:59:08 -0600700 mode_id, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500701}
702
703static Bool
704drmmode_property_ignore(drmModePropertyPtr prop)
705{
706 if (!prop)
Rob Clark74210d52012-01-08 17:59:08 -0600707 return TRUE;
Rob Clark487687e2011-07-17 17:29:02 -0500708 /* ignore blob prop */
709 if (prop->flags & DRM_MODE_PROP_BLOB)
710 return TRUE;
711 /* ignore standard property */
712 if (!strcmp(prop->name, "EDID") ||
Rob Clark74210d52012-01-08 17:59:08 -0600713 !strcmp(prop->name, "DPMS"))
Rob Clark487687e2011-07-17 17:29:02 -0500714 return TRUE;
715
716 return FALSE;
717}
718
719static void
720drmmode_output_create_resources(xf86OutputPtr output)
721{
722 drmmode_output_private_ptr drmmode_output = output->driver_private;
723 drmModeConnectorPtr mode_output = drmmode_output->mode_output;
724 drmmode_ptr drmmode = drmmode_output->drmmode;
725 drmModePropertyPtr drmmode_prop;
726 uint32_t value;
727 int i, j, err;
728
729 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
730 if (!drmmode_output->props)
731 return;
732
733 drmmode_output->num_props = 0;
734 for (i = 0, j = 0; i < mode_output->count_props; i++) {
735 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
736 if (drmmode_property_ignore(drmmode_prop)) {
737 drmModeFreeProperty(drmmode_prop);
738 continue;
739 }
740 drmmode_output->props[j].mode_prop = drmmode_prop;
741 drmmode_output->props[j].index = i;
742 drmmode_output->num_props++;
743 j++;
744 }
745
746 for (i = 0; i < drmmode_output->num_props; i++) {
747 drmmode_prop_ptr p = &drmmode_output->props[i];
748 drmmode_prop = p->mode_prop;
749
750 value = drmmode_output->mode_output->prop_values[p->index];
751
752 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
753 INT32 range[2];
754
755 p->num_atoms = 1;
756 p->atoms = calloc(p->num_atoms, sizeof(Atom));
757 if (!p->atoms)
758 continue;
759 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
760 range[0] = drmmode_prop->values[0];
761 range[1] = drmmode_prop->values[1];
762 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600763 FALSE, TRUE,
764 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
Rob Clark487687e2011-07-17 17:29:02 -0500765 2, range);
766 if (err != 0) {
767 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600768 "RRConfigureOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500769 }
770 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600771 XA_INTEGER, 32, PropModeReplace, 1,
772 &value, FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500773 if (err != 0) {
774 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600775 "RRChangeOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500776 }
777 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
778 p->num_atoms = drmmode_prop->count_enums + 1;
779 p->atoms = calloc(p->num_atoms, sizeof(Atom));
780 if (!p->atoms)
781 continue;
782 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
783 for (j = 1; j <= drmmode_prop->count_enums; j++) {
784 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
785 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
786 }
787 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600788 FALSE, FALSE,
789 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
Rob Clark487687e2011-07-17 17:29:02 -0500790 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
791 if (err != 0) {
792 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600793 "RRConfigureOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500794 }
795 for (j = 0; j < drmmode_prop->count_enums; j++)
796 if (drmmode_prop->enums[j].value == value)
797 break;
798 /* there's always a matching value */
799 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600800 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500801 if (err != 0) {
802 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600803 "RRChangeOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500804 }
805 }
806 }
807}
808
809static Bool
810drmmode_output_set_property(xf86OutputPtr output, Atom property,
Rob Clark74210d52012-01-08 17:59:08 -0600811 RRPropertyValuePtr value)
Rob Clark487687e2011-07-17 17:29:02 -0500812{
813 drmmode_output_private_ptr drmmode_output = output->driver_private;
814 drmmode_ptr drmmode = drmmode_output->drmmode;
815 int i, ret;
816
817 for (i = 0; i < drmmode_output->num_props; i++) {
818 drmmode_prop_ptr p = &drmmode_output->props[i];
819
820 if (p->atoms[0] != property)
821 continue;
822
823 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
824 uint32_t val;
825
826 if (value->type != XA_INTEGER || value->format != 32 ||
Rob Clark74210d52012-01-08 17:59:08 -0600827 value->size != 1)
Rob Clark487687e2011-07-17 17:29:02 -0500828 return FALSE;
829 val = *(uint32_t *)value->data;
830
831 ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
Rob Clark74210d52012-01-08 17:59:08 -0600832 p->mode_prop->prop_id, (uint64_t)val);
Rob Clark487687e2011-07-17 17:29:02 -0500833
834 if (ret)
835 return FALSE;
836
837 return TRUE;
838
839 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
840 Atom atom;
841 const char *name;
842 int j;
843
844 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
845 return FALSE;
846 memcpy(&atom, value->data, 4);
847 name = NameForAtom(atom);
848
849 /* search for matching name string, then set its value down */
850 for (j = 0; j < p->mode_prop->count_enums; j++) {
851 if (!strcmp(p->mode_prop->enums[j].name, name)) {
852 ret = drmModeConnectorSetProperty(drmmode->fd,
Rob Clark74210d52012-01-08 17:59:08 -0600853 drmmode_output->output_id,
854 p->mode_prop->prop_id,
855 p->mode_prop->enums[j].value);
Rob Clark487687e2011-07-17 17:29:02 -0500856
857 if (ret)
858 return FALSE;
859
860 return TRUE;
861 }
862 }
863
864 return FALSE;
865 }
866 }
867
868 return TRUE;
869}
870
871static Bool
872drmmode_output_get_property(xf86OutputPtr output, Atom property)
873{
874
875 drmmode_output_private_ptr drmmode_output = output->driver_private;
876 drmmode_ptr drmmode = drmmode_output->drmmode;
877 uint32_t value;
878 int err, i;
879
880 if (output->scrn->vtSema) {
881 drmModeFreeConnector(drmmode_output->mode_output);
882 drmmode_output->mode_output =
Rob Clark74210d52012-01-08 17:59:08 -0600883 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500884 }
885
886 for (i = 0; i < drmmode_output->num_props; i++) {
887 drmmode_prop_ptr p = &drmmode_output->props[i];
888 if (p->atoms[0] != property)
889 continue;
890
891 value = drmmode_output->mode_output->prop_values[p->index];
892
893 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
894 err = RRChangeOutputProperty(output->randr_output,
Rob Clark74210d52012-01-08 17:59:08 -0600895 property, XA_INTEGER, 32,
896 PropModeReplace, 1, &value,
897 FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500898
899 return !err;
900 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
901 int j;
902
903 /* search for matching name string, then set its value down */
904 for (j = 0; j < p->mode_prop->count_enums; j++) {
905 if (p->mode_prop->enums[j].value == value)
906 break;
907 }
908
909 err = RRChangeOutputProperty(output->randr_output, property,
Rob Clark74210d52012-01-08 17:59:08 -0600910 XA_ATOM, 32, PropModeReplace, 1,
911 &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500912
913 return !err;
914 }
915 }
916
917 return FALSE;
918}
919
920static const xf86OutputFuncsRec drmmode_output_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600921 .create_resources = drmmode_output_create_resources,
922 .dpms = drmmode_output_dpms,
923 .detect = drmmode_output_detect,
924 .mode_valid = drmmode_output_mode_valid,
925 .get_modes = drmmode_output_get_modes,
926 .set_property = drmmode_output_set_property,
927 .get_property = drmmode_output_get_property,
928 .destroy = drmmode_output_destroy
Rob Clark487687e2011-07-17 17:29:02 -0500929};
930
931// FIXME - Eliminate the following values that aren't accurate for OMAP4:
932const char *output_names[] = { "None",
Rob Clark74210d52012-01-08 17:59:08 -0600933 "VGA",
934 "DVI-I",
935 "DVI-D",
936 "DVI-A",
937 "Composite",
938 "SVIDEO",
939 "LVDS",
940 "CTV",
941 "DIN",
942 "DP",
943 "HDMI",
944 "HDMI",
945 "TV",
946 "eDP",
Rob Clark487687e2011-07-17 17:29:02 -0500947};
948#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
949
950static void
951drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
952{
Rob Clark74210d52012-01-08 17:59:08 -0600953 xf86OutputPtr output;
954 drmModeConnectorPtr koutput;
955 drmModeEncoderPtr kencoder;
956 drmmode_output_private_ptr drmmode_output;
957 char name[32];
Rob Clark487687e2011-07-17 17:29:02 -0500958
Rob Clark74210d52012-01-08 17:59:08 -0600959 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -0500960
Rob Clark74210d52012-01-08 17:59:08 -0600961 koutput = drmModeGetConnector(drmmode->fd,
962 drmmode->mode_res->connectors[num]);
963 if (!koutput)
964 return;
Rob Clark487687e2011-07-17 17:29:02 -0500965
Rob Clark74210d52012-01-08 17:59:08 -0600966 kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
967 if (!kencoder) {
968 drmModeFreeConnector(koutput);
969 return;
970 }
Rob Clark487687e2011-07-17 17:29:02 -0500971
Rob Clark74210d52012-01-08 17:59:08 -0600972 if (koutput->connector_type >= NUM_OUTPUT_NAMES)
973 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
974 koutput->connector_type_id);
975 else
976 snprintf(name, 32, "%s-%d",
977 output_names[koutput->connector_type],
978 koutput->connector_type_id);
Rob Clark487687e2011-07-17 17:29:02 -0500979
Rob Clark74210d52012-01-08 17:59:08 -0600980 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
981 if (!output) {
982 drmModeFreeEncoder(kencoder);
983 drmModeFreeConnector(koutput);
984 return;
985 }
Rob Clark487687e2011-07-17 17:29:02 -0500986
Rob Clark74210d52012-01-08 17:59:08 -0600987 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
988 if (!drmmode_output) {
989 xf86OutputDestroy(output);
990 drmModeFreeConnector(koutput);
991 drmModeFreeEncoder(kencoder);
992 return;
993 }
Rob Clark487687e2011-07-17 17:29:02 -0500994
Rob Clark74210d52012-01-08 17:59:08 -0600995 drmmode_output->output_id = drmmode->mode_res->connectors[num];
996 drmmode_output->mode_output = koutput;
997 drmmode_output->mode_encoder = kencoder;
998 drmmode_output->drmmode = drmmode;
Rob Clark487687e2011-07-17 17:29:02 -0500999
Rob Clark74210d52012-01-08 17:59:08 -06001000 output->mm_width = koutput->mmWidth;
1001 output->mm_height = koutput->mmHeight;
1002 output->driver_private = drmmode_output;
Rob Clark487687e2011-07-17 17:29:02 -05001003
Rob Clark74210d52012-01-08 17:59:08 -06001004 output->possible_crtcs = kencoder->possible_crtcs;
1005 output->possible_clones = kencoder->possible_clones;
1006 output->interlaceAllowed = TRUE;
Rob Clark487687e2011-07-17 17:29:02 -05001007
Rob Clark74210d52012-01-08 17:59:08 -06001008 TRACE_EXIT();
1009 return;
1010}
Rob Clark487687e2011-07-17 17:29:02 -05001011
David Garbett3688b332012-05-11 12:17:34 +01001012void set_scanout_bo(ScrnInfoPtr pScrn, struct omap_bo *bo)
1013{
1014 OMAPPtr pOMAP = OMAPPTR(pScrn);
1015
1016 /* It had better have a framebuffer if we're scanning it out */
1017 assert(omap_bo_get_fb(bo));
1018
1019 pOMAP->scanout = bo;
1020}
1021
Rob Clark487687e2011-07-17 17:29:02 -05001022static Bool
1023drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
1024{
1025 OMAPPtr pOMAP = OMAPPTR(pScrn);
1026 ScreenPtr pScreen = pScrn->pScreen;
David Garbett3688b332012-05-11 12:17:34 +01001027 struct omap_bo *new_scanout;
1028 int res;
Sean Paul3e107302012-08-30 12:08:12 -07001029 uint32_t pitch;
Brian Starkeycd684422012-09-20 09:28:04 +01001030 int i;
1031 xf86CrtcConfigPtr xf86_config;
Rob Clark487687e2011-07-17 17:29:02 -05001032
1033 TRACE_ENTER();
1034
1035 /* if fb required size has changed, realloc! */
1036
1037 DEBUG_MSG("Resize! %dx%d", width, height);
1038
1039 pScrn->virtualX = width;
1040 pScrn->virtualY = height;
1041
David Garbettc5901532012-05-29 13:00:52 +01001042 if ( (width != omap_bo_width(pOMAP->scanout))
1043 || (height != omap_bo_height(pOMAP->scanout))
1044 || (pScrn->bitsPerPixel != omap_bo_bpp(pOMAP->scanout)) ) {
Rob Clark487687e2011-07-17 17:29:02 -05001045
Shirish S29e4a232012-07-13 19:34:24 -07001046 pOMAP->has_resized = TRUE;
David Garbettc5901532012-05-29 13:00:52 +01001047 DEBUG_MSG("allocating new scanout buffer: %dx%d",
1048 width, height);
Rob Clark487687e2011-07-17 17:29:02 -05001049
1050 /* allocate new scanout buffer */
Sean Paul3e107302012-08-30 12:08:12 -07001051 new_scanout = omap_bo_new_with_dim(pOMAP->dev, width, height,
1052 pScrn->depth, pScrn->bitsPerPixel,
Rob Clark487687e2011-07-17 17:29:02 -05001053 OMAP_BO_SCANOUT | OMAP_BO_WC);
David Garbett3688b332012-05-11 12:17:34 +01001054
1055 if (!new_scanout) {
Rob Clark487687e2011-07-17 17:29:02 -05001056 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1057 "Error reallocating scanout buffer\n");
1058 return FALSE;
1059 }
David Garbettc5901532012-05-29 13:00:52 +01001060 pitch = omap_bo_pitch(new_scanout);
David Garbett3688b332012-05-11 12:17:34 +01001061
akshu agrawal6a5dead2012-08-09 17:02:21 +05301062 if (omap_bo_clear(new_scanout) || omap_bo_add_fb(new_scanout)) {
David Garbettae5a6362012-07-02 10:15:47 +01001063 omap_bo_unreference(new_scanout);
David Garbett3688b332012-05-11 12:17:34 +01001064 return FALSE;
David Garbettae5a6362012-07-02 10:15:47 +01001065 }
1066
1067 /* Handle dma_buf fd that may be attached to bo */
1068 if(omap_bo_has_dmabuf(pOMAP->scanout))
1069 {
1070 omap_bo_clear_dmabuf(pOMAP->scanout);
1071 res = omap_bo_set_dmabuf(new_scanout);
1072 if(res) {
1073 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1074 "Unable to attach dma_buf fd to new scanout buffer. "
1075 "Error: %d (%s)\n", res, strerror(res));
1076 omap_bo_unreference(new_scanout);
1077 return FALSE;
1078 }
1079 }
1080
1081 /* delete old scanout buffer */
1082 omap_bo_unreference(pOMAP->scanout);
David Garbett3688b332012-05-11 12:17:34 +01001083
1084 set_scanout_bo(pScrn, new_scanout);
1085
1086 pScrn->displayWidth = pitch / (pScrn->bitsPerPixel / 8);
David Garbettc5901532012-05-29 13:00:52 +01001087 }else{
1088 pitch = omap_bo_pitch(pOMAP->scanout);
Rob Clark487687e2011-07-17 17:29:02 -05001089 }
1090
1091 if (pScreen && pScreen->ModifyPixmapHeader) {
1092 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1093 pScreen->ModifyPixmapHeader(rootPixmap,
1094 pScrn->virtualX, pScrn->virtualY,
1095 pScrn->depth, pScrn->bitsPerPixel, pitch,
1096 omap_bo_map(pOMAP->scanout));
1097 }
1098
Brian Starkeycd684422012-09-20 09:28:04 +01001099 /* Framebuffer needs to be reset on all CRTCs, not just
1100 * those that have repositioned */
1101 xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1102 for (i = 0; i < xf86_config->num_crtc; i++) {
1103 xf86CrtcPtr crtc = xf86_config->crtc[i];
1104
1105 if (!crtc->enabled)
1106 continue;
1107
1108 drmmode_set_mode_major(crtc, &crtc->mode,
1109 crtc->rotation, crtc->x, crtc->y);
1110 }
1111
1112
Rob Clark487687e2011-07-17 17:29:02 -05001113 TRACE_EXIT();
1114 return TRUE;
Rob Clark74210d52012-01-08 17:59:08 -06001115}
Rob Clark487687e2011-07-17 17:29:02 -05001116
1117static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -06001118 drmmode_xf86crtc_resize
Rob Clark487687e2011-07-17 17:29:02 -05001119};
1120
1121
1122Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
1123{
Rob Clark74210d52012-01-08 17:59:08 -06001124 drmmode_ptr drmmode;
1125 int i;
Rob Clark487687e2011-07-17 17:29:02 -05001126
Rob Clark74210d52012-01-08 17:59:08 -06001127 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001128
Rob Clark74210d52012-01-08 17:59:08 -06001129 drmmode = calloc(1, sizeof *drmmode);
1130 drmmode->fd = fd;
Rob Clark487687e2011-07-17 17:29:02 -05001131
Rob Clark74210d52012-01-08 17:59:08 -06001132 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
Rob Clark487687e2011-07-17 17:29:02 -05001133
1134
Rob Clark74210d52012-01-08 17:59:08 -06001135 drmmode->cpp = cpp;
1136 drmmode->mode_res = drmModeGetResources(drmmode->fd);
1137 if (!drmmode->mode_res) {
1138 return FALSE;
1139 } else {
1140 DEBUG_MSG("Got KMS resources");
1141 DEBUG_MSG(" %d connectors, %d encoders",
1142 drmmode->mode_res->count_connectors,
1143 drmmode->mode_res->count_encoders);
1144 DEBUG_MSG(" %d crtcs, %d fbs",
1145 drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs);
1146 DEBUG_MSG(" %dx%d minimum resolution",
1147 drmmode->mode_res->min_width, drmmode->mode_res->min_height);
1148 DEBUG_MSG(" %dx%d maximum resolution",
1149 drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1150 }
1151 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
1152 drmmode->mode_res->max_height);
1153 for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1154 drmmode_crtc_init(pScrn, drmmode, i);
Rob Clark487687e2011-07-17 17:29:02 -05001155
Rob Clark74210d52012-01-08 17:59:08 -06001156 for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1157 drmmode_output_init(pScrn, drmmode, i);
Rob Clark487687e2011-07-17 17:29:02 -05001158
Rob Clark74210d52012-01-08 17:59:08 -06001159 xf86InitialConfiguration(pScrn, TRUE);
Rob Clark487687e2011-07-17 17:29:02 -05001160
Rob Clark74210d52012-01-08 17:59:08 -06001161 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -05001162
Rob Clark74210d52012-01-08 17:59:08 -06001163 return TRUE;
1164}
Rob Clark487687e2011-07-17 17:29:02 -05001165
1166void
Cooper Yuana83caa62012-06-28 17:19:06 +02001167drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y)
Rob Clark487687e2011-07-17 17:29:02 -05001168{
1169 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1170 xf86OutputPtr output = config->output[config->compat_output];
1171 xf86CrtcPtr crtc = output->crtc;
1172
1173 if (!crtc || !crtc->enabled)
1174 return;
1175
1176 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
1177}
1178
Rob Clark4b8f30a2011-08-28 12:51:26 -05001179/*
1180 * Page Flipping
1181 */
1182
1183static void
1184page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
Rob Clark74210d52012-01-08 17:59:08 -06001185 unsigned int tv_usec, void *user_data)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001186{
Rob Clark4b8f30a2011-08-28 12:51:26 -05001187 OMAPDRI2SwapComplete(user_data);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001188}
1189
1190static drmEventContext event_context = {
1191 .version = DRM_EVENT_CONTEXT_VERSION,
1192 .page_flip_handler = page_flip_handler,
1193};
1194
John Sheu022833e2012-08-15 11:40:11 -07001195int
Rob Clark4b8f30a2011-08-28 12:51:26 -05001196drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
1197{
1198 ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
1199 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1200 drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
1201 drmmode_ptr mode = crtc->drmmode;
John Sheu022833e2012-08-15 11:40:11 -07001202 int ret, i, failed = 0, num_flipped = 0;
Raymond Smith16a910e2012-05-09 13:04:51 +01001203 unsigned int flags = 0;
1204
John Sheu022833e2012-08-15 11:40:11 -07001205#if OMAP_USE_PAGE_FLIP_EVENTS
Raymond Smith16a910e2012-05-09 13:04:51 +01001206 flags |= DRM_MODE_PAGE_FLIP_EVENT;
1207#endif
Rob Clark4b8f30a2011-08-28 12:51:26 -05001208
1209 /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
1210 for (i = 0; i < config->num_crtc; i++) {
1211 crtc = config->crtc[i]->driver_private;
1212
Rob Clark4b8f30a2011-08-28 12:51:26 -05001213 ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
Raymond Smith16a910e2012-05-09 13:04:51 +01001214 fb_id, flags, priv);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001215 if (ret) {
1216 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
Rob Clark74210d52012-01-08 17:59:08 -06001217 "flip queue failed: %s\n", strerror(errno));
John Sheu022833e2012-08-15 11:40:11 -07001218 failed = 1;
1219 }
1220 else {
1221 num_flipped += 1;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001222 }
1223 }
1224
John Sheu022833e2012-08-15 11:40:11 -07001225 if (failed)
1226 return -(num_flipped + 1);
1227 else
1228 return num_flipped;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001229}
Rob Clark487687e2011-07-17 17:29:02 -05001230
1231/*
1232 * Hot Plug Event handling:
1233 */
1234
Rob Clark487687e2011-07-17 17:29:02 -05001235static void
1236drmmode_handle_uevents(int fd, void *closure)
1237{
Rob Clark74210d52012-01-08 17:59:08 -06001238 ScrnInfoPtr pScrn = closure;
1239 OMAPPtr pOMAP = OMAPPTR(pScrn);
1240 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1241 struct udev_device *dev;
1242 const char *hotplug;
1243 struct stat s;
1244 dev_t udev_devnum;
Rob Clark487687e2011-07-17 17:29:02 -05001245
Rob Clark74210d52012-01-08 17:59:08 -06001246 dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1247 if (!dev)
1248 return;
Rob Clark487687e2011-07-17 17:29:02 -05001249
Rob Clark74210d52012-01-08 17:59:08 -06001250 // FIXME - Do we need to keep this code, which Rob originally wrote
1251 // (i.e. up thru the "if" statement)?:
Rob Clark487687e2011-07-17 17:29:02 -05001252
Rob Clark74210d52012-01-08 17:59:08 -06001253 /*
1254 * Check to make sure this event is directed at our
1255 * device (by comparing dev_t values), then make
1256 * sure it's a hotplug event (HOTPLUG=1)
1257 */
1258 udev_devnum = udev_device_get_devnum(dev);
1259 fstat(pOMAP->drmFD, &s);
Rob Clark487687e2011-07-17 17:29:02 -05001260
Rob Clark74210d52012-01-08 17:59:08 -06001261 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
Rob Clark487687e2011-07-17 17:29:02 -05001262
Rob Clark74210d52012-01-08 17:59:08 -06001263 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug,
1264 memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)));
Rob Clark487687e2011-07-17 17:29:02 -05001265
Rob Clark74210d52012-01-08 17:59:08 -06001266 if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
1267 hotplug && atoi(hotplug) == 1) {
1268 RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE);
1269 }
1270 udev_device_unref(dev);
1271}
Rob Clark487687e2011-07-17 17:29:02 -05001272
Rob Clark4b8f30a2011-08-28 12:51:26 -05001273static void
Rob Clark487687e2011-07-17 17:29:02 -05001274drmmode_uevent_init(ScrnInfoPtr pScrn)
1275{
Rob Clark74210d52012-01-08 17:59:08 -06001276 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1277 struct udev *u;
1278 struct udev_monitor *mon;
Rob Clark487687e2011-07-17 17:29:02 -05001279
Rob Clark74210d52012-01-08 17:59:08 -06001280 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001281
Rob Clark74210d52012-01-08 17:59:08 -06001282 u = udev_new();
1283 if (!u)
1284 return;
1285 mon = udev_monitor_new_from_netlink(u, "udev");
1286 if (!mon) {
1287 udev_unref(u);
1288 return;
1289 }
Rob Clark487687e2011-07-17 17:29:02 -05001290
Rob Clark74210d52012-01-08 17:59:08 -06001291 if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1292 "drm",
1293 "drm_minor") < 0 ||
1294 udev_monitor_enable_receiving(mon) < 0) {
1295 udev_monitor_unref(mon);
1296 udev_unref(u);
1297 return;
1298 }
Rob Clark487687e2011-07-17 17:29:02 -05001299
Rob Clark74210d52012-01-08 17:59:08 -06001300 drmmode->uevent_handler =
1301 xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1302 drmmode_handle_uevents, pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001303
Rob Clark74210d52012-01-08 17:59:08 -06001304 drmmode->uevent_monitor = mon;
Rob Clark487687e2011-07-17 17:29:02 -05001305
Rob Clark74210d52012-01-08 17:59:08 -06001306 TRACE_EXIT();
1307}
Rob Clark487687e2011-07-17 17:29:02 -05001308
Rob Clark4b8f30a2011-08-28 12:51:26 -05001309static void
Rob Clark487687e2011-07-17 17:29:02 -05001310drmmode_uevent_fini(ScrnInfoPtr pScrn)
1311{
Rob Clark74210d52012-01-08 17:59:08 -06001312 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001313
Rob Clark74210d52012-01-08 17:59:08 -06001314 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001315
Rob Clark74210d52012-01-08 17:59:08 -06001316 if (drmmode->uevent_handler) {
1317 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1318 xf86RemoveGeneralHandler(drmmode->uevent_handler);
Rob Clark487687e2011-07-17 17:29:02 -05001319
Rob Clark74210d52012-01-08 17:59:08 -06001320 udev_monitor_unref(drmmode->uevent_monitor);
1321 udev_unref(u);
1322 }
Rob Clark487687e2011-07-17 17:29:02 -05001323
Rob Clark74210d52012-01-08 17:59:08 -06001324 TRACE_EXIT();
1325}
Rob Clark4b8f30a2011-08-28 12:51:26 -05001326
1327static void
1328drmmode_wakeup_handler(pointer data, int err, pointer p)
1329{
Rob Clark67b875f2012-04-20 19:13:57 -05001330 ScrnInfoPtr pScrn = data;
1331 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001332 fd_set *read_mask = p;
1333
Rob Clark67b875f2012-04-20 19:13:57 -05001334 if (pScrn == NULL || err < 0)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001335 return;
1336
1337 if (FD_ISSET(drmmode->fd, read_mask))
1338 drmHandleEvent(drmmode->fd, &event_context);
1339}
1340
1341void
Rob Clark67b875f2012-04-20 19:13:57 -05001342drmmode_wait_for_event(ScrnInfoPtr pScrn)
1343{
1344 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1345 drmHandleEvent(drmmode->fd, &event_context);
1346}
1347
1348void
Rob Clark4b8f30a2011-08-28 12:51:26 -05001349drmmode_screen_init(ScrnInfoPtr pScrn)
1350{
Rob Clark74210d52012-01-08 17:59:08 -06001351 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001352
1353 drmmode_uevent_init(pScrn);
1354
Rob Clark74210d52012-01-08 17:59:08 -06001355 AddGeneralSocket(drmmode->fd);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001356
Rob Clark74210d52012-01-08 17:59:08 -06001357 /* Register a wakeup handler to get informed on DRM events */
1358 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1359 drmmode_wakeup_handler, pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001360}
1361
1362void
1363drmmode_screen_fini(ScrnInfoPtr pScrn)
1364{
1365 drmmode_uevent_fini(pScrn);
1366}