blob: 3569c3851ad1ad205043dbd8a741479f69413211 [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
Dave Barnish2742d152013-03-13 13:36:58 +000035/* TODO: MIDEGL-1430: cleanup #includes, remove unnecessary ones */
Rob Clark74210d52012-01-08 17:59:08 -060036
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
Rob Clark487687e2011-07-17 17:29:02 -050055#include "micmap.h"
56
57#include "xf86DDC.h"
58
Rob Clark487687e2011-07-17 17:29:02 -050059#include "xf86RandR12.h"
Rob Clark487687e2011-07-17 17:29:02 -050060#include "dixstruct.h"
61#include "scrnintstr.h"
Rob Clark487687e2011-07-17 17:29:02 -050062#include "fb.h"
Rob Clark487687e2011-07-17 17:29:02 -050063#include "xf86cmap.h"
Rob Clark487687e2011-07-17 17:29:02 -050064
Rob Clark487687e2011-07-17 17:29:02 -050065#include "xf86Cursor.h"
66#include "xf86DDC.h"
67
68#include "region.h"
69
70#include <X11/extensions/randr.h>
71
72#ifdef HAVE_XEXTPROTO_71
73#include <X11/extensions/dpmsconst.h>
74#else
75#define DPMS_SERVER
76#include <X11/extensions/dpms.h>
77#endif
78
Paul Gearyf8b99692013-04-15 10:55:17 +010079#include "armsoc_driver.h"
Rob Clark487687e2011-07-17 17:29:02 -050080
Rob Clark487687e2011-07-17 17:29:02 -050081#include "xf86Crtc.h"
Rob Clark487687e2011-07-17 17:29:02 -050082
83#include "xf86drmMode.h"
Rob Clark687c6082012-01-08 19:33:18 -060084#include "drm_fourcc.h"
Rob Clark487687e2011-07-17 17:29:02 -050085#include "X11/Xatom.h"
86
Rob Clark487687e2011-07-17 17:29:02 -050087#include <libudev.h>
88
Ray Smith3c33c3d2013-03-26 16:06:37 +000089#include "drmmode_driver.h"
90
Rob Clark487687e2011-07-17 17:29:02 -050091typedef struct {
Rob Clark687c6082012-01-08 19:33:18 -060092 /* hardware cursor: */
93 drmModePlane *ovr;
Paul Geary8ffd91c2013-04-11 16:03:15 +010094 struct armsoc_bo *bo;
Rob Clark687c6082012-01-08 19:33:18 -060095 uint32_t fb_id;
96 int x, y;
Rob Clark687c6082012-01-08 19:33:18 -060097} drmmode_cursor_rec, *drmmode_cursor_ptr;
98
99typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600100 int fd;
Rob Clark74210d52012-01-08 17:59:08 -0600101 drmModeResPtr mode_res;
102 int cpp;
103 struct udev_monitor *uevent_monitor;
104 InputHandlerProc uevent_handler;
Rob Clark687c6082012-01-08 19:33:18 -0600105 drmmode_cursor_ptr cursor;
Rob Clark487687e2011-07-17 17:29:02 -0500106} drmmode_rec, *drmmode_ptr;
107
108typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600109 drmmode_ptr drmmode;
110 drmModeCrtcPtr mode_crtc;
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700111 int cursor_visible;
Rob Clark487687e2011-07-17 17:29:02 -0500112} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
113
114typedef struct {
115 drmModePropertyPtr mode_prop;
116 int index; /* Index within the kernel-side property arrays for
Rob Clark74210d52012-01-08 17:59:08 -0600117 * this connector. */
Rob Clark487687e2011-07-17 17:29:02 -0500118 int num_atoms; /* if range prop, num_atoms == 1; if enum prop,
Rob Clark74210d52012-01-08 17:59:08 -0600119 * num_atoms == num_enums + 1 */
Rob Clark487687e2011-07-17 17:29:02 -0500120 Atom *atoms;
121} drmmode_prop_rec, *drmmode_prop_ptr;
122
123typedef struct {
Rob Clark74210d52012-01-08 17:59:08 -0600124 drmmode_ptr drmmode;
125 int output_id;
126 drmModeConnectorPtr mode_output;
127 drmModeEncoderPtr mode_encoder;
128 drmModePropertyBlobPtr edid_blob;
129 int num_props;
130 drmmode_prop_ptr props;
Rob Clark487687e2011-07-17 17:29:02 -0500131} drmmode_output_private_rec, *drmmode_output_private_ptr;
132
133static void drmmode_output_dpms(xf86OutputPtr output, int mode);
Rob Clark487687e2011-07-17 17:29:02 -0500134
Rob Clark687c6082012-01-08 19:33:18 -0600135static drmmode_ptr
136drmmode_from_scrn(ScrnInfoPtr pScrn)
137{
138 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
139 drmmode_crtc_private_ptr drmmode_crtc;
140
141 drmmode_crtc = xf86_config->crtc[0]->driver_private;
142 return drmmode_crtc->drmmode;
143}
144
Rob Clark487687e2011-07-17 17:29:02 -0500145static void
146drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600147 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500148{
Rob Clark74210d52012-01-08 17:59:08 -0600149 memset(mode, 0, sizeof(DisplayModeRec));
150 mode->status = MODE_OK;
Rob Clark487687e2011-07-17 17:29:02 -0500151
Rob Clark74210d52012-01-08 17:59:08 -0600152 mode->Clock = kmode->clock;
Rob Clark487687e2011-07-17 17:29:02 -0500153
Rob Clark74210d52012-01-08 17:59:08 -0600154 mode->HDisplay = kmode->hdisplay;
155 mode->HSyncStart = kmode->hsync_start;
156 mode->HSyncEnd = kmode->hsync_end;
157 mode->HTotal = kmode->htotal;
158 mode->HSkew = kmode->hskew;
Rob Clark487687e2011-07-17 17:29:02 -0500159
Rob Clark74210d52012-01-08 17:59:08 -0600160 mode->VDisplay = kmode->vdisplay;
161 mode->VSyncStart = kmode->vsync_start;
162 mode->VSyncEnd = kmode->vsync_end;
163 mode->VTotal = kmode->vtotal;
164 mode->VScan = kmode->vscan;
Rob Clark487687e2011-07-17 17:29:02 -0500165
Dave Barnish01b5c172013-04-10 11:01:17 +0100166 mode->Flags = kmode->flags;
Rob Clark74210d52012-01-08 17:59:08 -0600167 mode->name = strdup(kmode->name);
Rob Clark487687e2011-07-17 17:29:02 -0500168
Rob Clark74210d52012-01-08 17:59:08 -0600169 DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500170
Rob Clark74210d52012-01-08 17:59:08 -0600171 if (kmode->type & DRM_MODE_TYPE_DRIVER)
172 mode->type = M_T_DRIVER;
173 if (kmode->type & DRM_MODE_TYPE_PREFERRED)
174 mode->type |= M_T_PREFERRED;
Rob Clark487687e2011-07-17 17:29:02 -0500175
Rob Clark74210d52012-01-08 17:59:08 -0600176 xf86SetModeCrtc (mode, pScrn->adjustFlags);
177}
Rob Clark487687e2011-07-17 17:29:02 -0500178
179static void
180drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600181 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500182{
Rob Clark74210d52012-01-08 17:59:08 -0600183 memset(kmode, 0, sizeof(*kmode));
Rob Clark487687e2011-07-17 17:29:02 -0500184
Rob Clark74210d52012-01-08 17:59:08 -0600185 kmode->clock = mode->Clock;
186 kmode->hdisplay = mode->HDisplay;
187 kmode->hsync_start = mode->HSyncStart;
188 kmode->hsync_end = mode->HSyncEnd;
189 kmode->htotal = mode->HTotal;
190 kmode->hskew = mode->HSkew;
Rob Clark487687e2011-07-17 17:29:02 -0500191
Rob Clark74210d52012-01-08 17:59:08 -0600192 kmode->vdisplay = mode->VDisplay;
193 kmode->vsync_start = mode->VSyncStart;
194 kmode->vsync_end = mode->VSyncEnd;
195 kmode->vtotal = mode->VTotal;
196 kmode->vscan = mode->VScan;
Rob Clark487687e2011-07-17 17:29:02 -0500197
Dave Barnish01b5c172013-04-10 11:01:17 +0100198 kmode->flags = mode->Flags;
Rob Clark74210d52012-01-08 17:59:08 -0600199 if (mode->name)
200 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
201 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
202}
Rob Clark487687e2011-07-17 17:29:02 -0500203
204static void
205drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
206{
Dave Barnish2742d152013-03-13 13:36:58 +0000207 // TODO: MIDEGL-1431: Implement this function
Rob Clark74210d52012-01-08 17:59:08 -0600208}
Rob Clark487687e2011-07-17 17:29:02 -0500209
210static Bool
211drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rob Clark74210d52012-01-08 17:59:08 -0600212 Rotation rotation, int x, int y)
Rob Clark487687e2011-07-17 17:29:02 -0500213{
214 ScrnInfoPtr pScrn = crtc->scrn;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100215 ARMSOCPtr pARMSOC = ARMSOCPTR(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -0500216 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
217 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
218 drmmode_ptr drmmode = drmmode_crtc->drmmode;
219 int saved_x, saved_y;
220 Rotation saved_rotation;
221 DisplayModeRec saved_mode;
222 uint32_t *output_ids = NULL;
223 int output_count = 0;
224 int ret = TRUE;
225 int i;
David Garbett7171c522012-05-11 13:12:50 +0100226 uint32_t fb_id;
Rob Clark487687e2011-07-17 17:29:02 -0500227 drmModeModeInfo kmode;
228
229 TRACE_ENTER();
230
Paul Geary8ffd91c2013-04-11 16:03:15 +0100231 fb_id = armsoc_bo_get_fb(pARMSOC->scanout);
David Garbett7171c522012-05-11 13:12:50 +0100232
233 if (fb_id == 0) {
David Garbett7171c522012-05-11 13:12:50 +0100234
235 DEBUG_MSG("create framebuffer: %dx%d",
236 pScrn->virtualX, pScrn->virtualY);
237
Paul Geary8ffd91c2013-04-11 16:03:15 +0100238 ret = armsoc_bo_add_fb(pARMSOC->scanout);
Sean Paul3e107302012-08-30 12:08:12 -0700239 if (ret)
David Garbett7171c522012-05-11 13:12:50 +0100240 return FALSE;
Dave Barnish523c9ff2013-03-12 10:59:03 +0000241
Paul Geary8ffd91c2013-04-11 16:03:15 +0100242 fb_id = armsoc_bo_get_fb(pARMSOC->scanout);
Paul Geary6fe52f32013-04-03 11:12:24 +0100243 if (0 == fb_id)
244 return FALSE;
David Garbett7171c522012-05-11 13:12:50 +0100245 }
Rob Clark487687e2011-07-17 17:29:02 -0500246
247 /* Save the current mode in case there's a problem: */
248 saved_mode = crtc->mode;
249 saved_x = crtc->x;
250 saved_y = crtc->y;
251 saved_rotation = crtc->rotation;
252
253 /* Set the new mode: */
254 crtc->mode = *mode;
255 crtc->x = x;
256 crtc->y = y;
257 crtc->rotation = rotation;
258
259 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
260 if (!output_ids) {
Dave Barnish523c9ff2013-03-12 10:59:03 +0000261 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
262 "memory allocation failed in drmmode_set_mode_major()\n");
Rob Clark487687e2011-07-17 17:29:02 -0500263 ret = FALSE;
264 goto done;
265 }
266
267 for (i = 0; i < xf86_config->num_output; i++) {
268 xf86OutputPtr output = xf86_config->output[i];
269 drmmode_output_private_ptr drmmode_output;
270
271 if (output->crtc != crtc)
272 continue;
273
274 drmmode_output = output->driver_private;
275 output_ids[output_count] =
276 drmmode_output->mode_output->connector_id;
277 output_count++;
278 }
279
Dave Barnish523c9ff2013-03-12 10:59:03 +0000280 if (!xf86CrtcRotate(crtc)){
281 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
282 "failed to assign rotation in drmmode_set_mode_major()\n");
283 ret = FALSE;
Rob Clark487687e2011-07-17 17:29:02 -0500284 goto done;
Dave Barnish523c9ff2013-03-12 10:59:03 +0000285 }
Rob Clark487687e2011-07-17 17:29:02 -0500286
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200287 if (crtc->funcs->gamma_set)
288 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
289 crtc->gamma_blue, crtc->gamma_size);
Rob Clark487687e2011-07-17 17:29:02 -0500290
291 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
292
Rob Clark487687e2011-07-17 17:29:02 -0500293 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
294 fb_id, x, y, output_ids, output_count, &kmode);
295 if (ret) {
296 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
297 "failed to set mode: %s\n", strerror(-ret));
Dave Barnish523c9ff2013-03-12 10:59:03 +0000298 ret = FALSE;
299 goto done;
Rob Clark487687e2011-07-17 17:29:02 -0500300 } else {
301 ret = TRUE;
302 }
303
Rob Clark487687e2011-07-17 17:29:02 -0500304 /* Turn on any outputs on this crtc that may have been disabled: */
305 for (i = 0; i < xf86_config->num_output; i++) {
306 xf86OutputPtr output = xf86_config->output[i];
307
308 if (output->crtc != crtc)
309 continue;
310
311 drmmode_output_dpms(output, DPMSModeOn);
312 }
313
Dave Barnishaf046152013-05-31 09:12:44 +0100314 /* if hw cursor is initialized, reload it */
315 if(drmmode->cursor) {
316 xf86_reload_cursors(pScrn->pScreen);
317 }
Rob Clark487687e2011-07-17 17:29:02 -0500318
319done:
320 if (output_ids) {
321 free(output_ids);
322 }
323 if (!ret) {
Dave Barnish523c9ff2013-03-12 10:59:03 +0000324 /* If there was a problem, restore the old mode: */
Rob Clark487687e2011-07-17 17:29:02 -0500325 crtc->x = saved_x;
326 crtc->y = saved_y;
327 crtc->rotation = saved_rotation;
328 crtc->mode = saved_mode;
329 }
330
331 TRACE_EXIT();
332 return ret;
Rob Clark74210d52012-01-08 17:59:08 -0600333}
Rob Clark487687e2011-07-17 17:29:02 -0500334
335static void
Rob Clark487687e2011-07-17 17:29:02 -0500336drmmode_hide_cursor(xf86CrtcPtr crtc)
337{
Rob Clark74210d52012-01-08 17:59:08 -0600338 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
339 drmmode_ptr drmmode = drmmode_crtc->drmmode;
Rob Clark687c6082012-01-08 19:33:18 -0600340 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark487687e2011-07-17 17:29:02 -0500341
Rob Clark687c6082012-01-08 19:33:18 -0600342 if (!cursor)
343 return;
344
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700345 drmmode_crtc->cursor_visible = FALSE;
Rob Clark687c6082012-01-08 19:33:18 -0600346
347 /* set plane's fb_id to 0 to disable it */
348 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
349 drmmode_crtc->mode_crtc->crtc_id, 0, 0,
350 0, 0, 0, 0, 0, 0, 0, 0);
Rob Clark74210d52012-01-08 17:59:08 -0600351}
Rob Clark487687e2011-07-17 17:29:02 -0500352
353static void
354drmmode_show_cursor(xf86CrtcPtr crtc)
355{
Rob Clark74210d52012-01-08 17:59:08 -0600356 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
357 drmmode_ptr drmmode = drmmode_crtc->drmmode;
Rob Clark687c6082012-01-08 19:33:18 -0600358 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark60f5bad2012-01-22 18:35:28 -0600359 int crtc_x, crtc_y, src_x, src_y, w, h;
Rob Clark487687e2011-07-17 17:29:02 -0500360
Rob Clark687c6082012-01-08 19:33:18 -0600361 if (!cursor)
362 return;
Rob Clark487687e2011-07-17 17:29:02 -0500363
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700364 drmmode_crtc->cursor_visible = TRUE;
Rob Clark687c6082012-01-08 19:33:18 -0600365
Rob Clark60f5bad2012-01-22 18:35:28 -0600366 w = CURSORW;
367 h = CURSORH;
368 crtc_x = cursor->x;
369 crtc_y = cursor->y;
370 src_x = 0;
371 src_y = 0;
372
373 if (crtc_x < 0) {
374 src_x += -crtc_x;
375 w -= -crtc_x;
376 crtc_x = 0;
377 }
378
379 if (crtc_y < 0) {
380 src_y += -crtc_y;
381 h -= -crtc_y;
382 crtc_y = 0;
383 }
384
385 if ((crtc_x + w) > crtc->mode.HDisplay) {
386 w = crtc->mode.HDisplay - crtc_x;
387 }
388
389 if ((crtc_y + h) > crtc->mode.VDisplay) {
390 h = crtc->mode.VDisplay - crtc_y;
391 }
392
Rob Clark687c6082012-01-08 19:33:18 -0600393 /* note src coords (last 4 args) are in Q16 format */
394 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
395 drmmode_crtc->mode_crtc->crtc_id, cursor->fb_id, 0,
Rob Clark60f5bad2012-01-22 18:35:28 -0600396 crtc_x, crtc_y, w, h, src_x<<16, src_y<<16, w<<16, h<<16);
Rob Clark687c6082012-01-08 19:33:18 -0600397}
398
399static void
400drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
401{
402 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
403 drmmode_ptr drmmode = drmmode_crtc->drmmode;
404 drmmode_cursor_ptr cursor = drmmode->cursor;
405
406 if (!cursor)
407 return;
408
409 cursor->x = x;
410 cursor->y = y;
411
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700412 if (drmmode_crtc->cursor_visible)
Rob Clark687c6082012-01-08 19:33:18 -0600413 drmmode_show_cursor(crtc);
414}
415
416static void
417drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
418{
John Rees292ae502013-03-21 16:24:35 +0000419 uint32_t * d;
Rob Clark687c6082012-01-08 19:33:18 -0600420 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
421 drmmode_ptr drmmode = drmmode_crtc->drmmode;
422 drmmode_cursor_ptr cursor = drmmode->cursor;
Rob Clark979add52012-02-21 18:35:24 -0600423 int visible;
Rob Clark687c6082012-01-08 19:33:18 -0600424
425 if (!cursor)
426 return;
427
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700428 visible = drmmode_crtc->cursor_visible;
Rob Clark979add52012-02-21 18:35:24 -0600429
430 if (visible)
Rob Clark687c6082012-01-08 19:33:18 -0600431 drmmode_hide_cursor(crtc);
432
Paul Geary8ffd91c2013-04-11 16:03:15 +0100433 d = armsoc_bo_map(cursor->bo);
Paul Geary6fe52f32013-04-03 11:12:24 +0100434 if(!d) {
435 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
436 "load_cursor_argb map failure\n");
437 if (visible)
438 drmmode_show_cursor(crtc);
439 return;
440 }
John Rees292ae502013-03-21 16:24:35 +0000441
442#if ( DRM_CURSOR_PLANE_FORMAT == HW_CURSOR_ARGB )
Paul Geary8ffd91c2013-04-11 16:03:15 +0100443 memcpy(d, image, armsoc_bo_size(cursor->bo));
John Rees292ae502013-03-21 16:24:35 +0000444#elif ( DRM_CURSOR_PLANE_FORMAT == HW_CURSOR_PL111 )
Paul Geary8ffd91c2013-04-11 16:03:15 +0100445 drmmode_argb_cursor_to_pl111_lbbp(crtc, d, image, armsoc_bo_size(cursor->bo) );
John Rees292ae502013-03-21 16:24:35 +0000446#else
447 #error Please provide a method to set your cursor image.
448#endif
Rob Clark687c6082012-01-08 19:33:18 -0600449
Rob Clark979add52012-02-21 18:35:24 -0600450 if (visible)
Rob Clark687c6082012-01-08 19:33:18 -0600451 drmmode_show_cursor(crtc);
452}
453
454Bool
455drmmode_cursor_init(ScreenPtr pScreen)
456{
457 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
Paul Geary8ffd91c2013-04-11 16:03:15 +0100458 ARMSOCPtr pARMSOC = ARMSOCPTR(pScrn);
Rob Clark687c6082012-01-08 19:33:18 -0600459 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
460 drmmode_cursor_ptr cursor;
461 drmModePlaneRes *plane_resources;
462 drmModePlane *ovr;
463
464 /* technically we probably don't have any size limit.. since we
465 * are just using an overlay... but xserver will always create
466 * cursor images in the max size, so don't use width/height values
467 * that are too big
468 */
Rob Clark60f5bad2012-01-22 18:35:28 -0600469 int w = CURSORW, h = CURSORH;
Rob Clark687c6082012-01-08 19:33:18 -0600470 uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */
471
472 if (drmmode->cursor) {
473 INFO_MSG("cursor already initialized");
474 return TRUE;
475 }
476
Ray Smith003cf5e2013-03-19 10:44:07 +0000477 if(!xf86LoaderCheckSymbol("drmModeGetPlaneResources")) {
Dave Barnishfd50b132013-05-16 15:00:02 +0100478 ERROR_MSG("HW cursor not supported (needs libdrm 2.4.30 or higher)");
Ray Smith003cf5e2013-03-19 10:44:07 +0000479 return FALSE;
480 }
Rob Clark687c6082012-01-08 19:33:18 -0600481
482 /* find an unused plane which can be used as a mouse cursor. Note
483 * that we cheat a bit, in order to not burn one overlay per crtc,
484 * and only show the mouse cursor on one crtc at a time
485 */
486 plane_resources = drmModeGetPlaneResources(drmmode->fd);
487 if (!plane_resources) {
Dave Barnishfd50b132013-05-16 15:00:02 +0100488 ERROR_MSG("HW cursor: drmModeGetPlaneResources failed: %s", strerror(errno));
Rob Clark687c6082012-01-08 19:33:18 -0600489 return FALSE;
490 }
491
492 if (plane_resources->count_planes < 1) {
493 ERROR_MSG("not enough planes for HW cursor");
Ray Smith003cf5e2013-03-19 10:44:07 +0000494 drmModeFreePlaneResources(plane_resources);
Rob Clark687c6082012-01-08 19:33:18 -0600495 return FALSE;
496 }
497
498 ovr = drmModeGetPlane(drmmode->fd, plane_resources->planes[0]);
499 if (!ovr) {
Dave Barnishfd50b132013-05-16 15:00:02 +0100500 ERROR_MSG("HW cursor: drmModeGetPlane failed: %s", strerror(errno));
Ray Smith003cf5e2013-03-19 10:44:07 +0000501 drmModeFreePlaneResources(plane_resources);
502 return FALSE;
503 }
504
Paul Geary8ffd91c2013-04-11 16:03:15 +0100505 if (pARMSOC->drmmode->init_plane_for_cursor &&
506 pARMSOC->drmmode->init_plane_for_cursor(drmmode->fd, ovr->plane_id)) {
Ray Smithb93cd892013-04-03 10:06:18 +0100507 ERROR_MSG("Failed driver-specific cursor initialization");
508 drmModeFreePlaneResources(plane_resources);
509 return FALSE;
510 }
511
Ray Smith003cf5e2013-03-19 10:44:07 +0000512 cursor = calloc(1, sizeof(drmmode_cursor_rec));
513 if (!cursor) {
Dave Barnishfd50b132013-05-16 15:00:02 +0100514 ERROR_MSG("HW cursor: calloc failed");
Ray Smith003cf5e2013-03-19 10:44:07 +0000515 drmModeFreePlane(ovr);
516 drmModeFreePlaneResources(plane_resources);
Rob Clark687c6082012-01-08 19:33:18 -0600517 return FALSE;
518 }
519
520 cursor->ovr = ovr;
Paul Geary8ffd91c2013-04-11 16:03:15 +0100521 cursor->bo = armsoc_bo_new_with_dim(pARMSOC->dev, w, h, 0, 32, ARMSOC_BO_SCANOUT );
Rob Clark687c6082012-01-08 19:33:18 -0600522
Ray Smith003cf5e2013-03-19 10:44:07 +0000523 if (!cursor->bo) {
Dave Barnishfd50b132013-05-16 15:00:02 +0100524 ERROR_MSG("HW cursor: buffer allocation failed");
Ray Smith003cf5e2013-03-19 10:44:07 +0000525 free(cursor);
526 drmModeFreePlane(ovr);
527 drmModeFreePlaneResources(plane_resources);
528 return FALSE;
529 }
530
Paul Geary8ffd91c2013-04-11 16:03:15 +0100531 handles[0] = armsoc_bo_handle(cursor->bo);
532 pitches[0] = armsoc_bo_pitch(cursor->bo);
Rob Clark687c6082012-01-08 19:33:18 -0600533 offsets[0] = 0;
534
535 if (drmModeAddFB2(drmmode->fd, w, h, DRM_FORMAT_ARGB8888,
536 handles, pitches, offsets, &cursor->fb_id, 0)) {
Dave Barnishfd50b132013-05-16 15:00:02 +0100537 ERROR_MSG("HW cursor: drmModeAddFB2 failed: %s", strerror(errno));
Paul Geary8ffd91c2013-04-11 16:03:15 +0100538 armsoc_bo_unreference(cursor->bo);
Ray Smith003cf5e2013-03-19 10:44:07 +0000539 free(cursor);
540 drmModeFreePlane(ovr);
541 drmModeFreePlaneResources(plane_resources);
Rob Clark687c6082012-01-08 19:33:18 -0600542 return FALSE;
543 }
544
Ray Smith003cf5e2013-03-19 10:44:07 +0000545 if (!xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) {
546 ERROR_MSG("xf86_cursors_init() failed");
547 if(drmModeRmFB(drmmode->fd, cursor->fb_id)) {
548 ERROR_MSG("drmModeRmFB() failed");
549 }
Paul Geary8ffd91c2013-04-11 16:03:15 +0100550 armsoc_bo_unreference(cursor->bo);
Ray Smith003cf5e2013-03-19 10:44:07 +0000551 free(cursor);
552 drmModeFreePlane(ovr);
553 drmModeFreePlaneResources(plane_resources);
554 return FALSE;
Rob Clark687c6082012-01-08 19:33:18 -0600555 }
556
Ray Smith003cf5e2013-03-19 10:44:07 +0000557 INFO_MSG("HW cursor initialized");
558 drmmode->cursor = cursor;
Dave Barnishfd50b132013-05-16 15:00:02 +0100559 drmModeFreePlaneResources(plane_resources);
Ray Smith003cf5e2013-03-19 10:44:07 +0000560 return TRUE;
Rob Clark74210d52012-01-08 17:59:08 -0600561}
Rob Clark487687e2011-07-17 17:29:02 -0500562
Dave Barnishfd50b132013-05-16 15:00:02 +0100563void drmmode_cursor_fini(ScreenPtr pScreen)
564{
565 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
566 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
567 drmmode_cursor_ptr cursor = drmmode->cursor;
568
569 if(!cursor ) {
570 return;
571 }
572 drmmode->cursor = NULL;
573 xf86_cursors_fini(pScreen);
574 drmModeRmFB(drmmode->fd, cursor->fb_id);
575 armsoc_bo_unreference(cursor->bo);
576 drmModeFreePlane(cursor->ovr);
577 free(cursor);
578}
579
580
Paul Geary8ffd91c2013-04-11 16:03:15 +0100581#if 1==ARMSOC_SUPPORT_GAMMA
Rob Clark487687e2011-07-17 17:29:02 -0500582static void
583drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
Rob Clark74210d52012-01-08 17:59:08 -0600584 int size)
Rob Clark487687e2011-07-17 17:29:02 -0500585{
586 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
587 drmmode_ptr drmmode = drmmode_crtc->drmmode;
588 int ret;
589
590 ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
Rob Clark74210d52012-01-08 17:59:08 -0600591 size, red, green, blue);
Rob Clark487687e2011-07-17 17:29:02 -0500592 if (ret != 0) {
593 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600594 "failed to set gamma: %s\n", strerror(-ret));
Rob Clark487687e2011-07-17 17:29:02 -0500595 }
596}
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200597#endif
Rob Clark487687e2011-07-17 17:29:02 -0500598
599static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600600 .dpms = drmmode_crtc_dpms,
601 .set_mode_major = drmmode_set_mode_major,
602 .set_cursor_position = drmmode_set_cursor_position,
603 .show_cursor = drmmode_show_cursor,
604 .hide_cursor = drmmode_hide_cursor,
605 .load_cursor_argb = drmmode_load_cursor_argb,
Paul Geary8ffd91c2013-04-11 16:03:15 +0100606#if 1==ARMSOC_SUPPORT_GAMMA
Rob Clark74210d52012-01-08 17:59:08 -0600607 .gamma_set = drmmode_gamma_set,
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200608#endif
Rob Clark487687e2011-07-17 17:29:02 -0500609};
610
611
612static void
613drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
614{
Rob Clark74210d52012-01-08 17:59:08 -0600615 xf86CrtcPtr crtc;
616 drmmode_crtc_private_ptr drmmode_crtc;
Rob Clark487687e2011-07-17 17:29:02 -0500617
Rob Clark74210d52012-01-08 17:59:08 -0600618 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -0500619
Rob Clark74210d52012-01-08 17:59:08 -0600620 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
621 if (crtc == NULL)
622 return;
623
624 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
625 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd,
626 drmmode->mode_res->crtcs[num]);
627 drmmode_crtc->drmmode = drmmode;
Dave Barnishf0952c12013-05-10 15:52:23 +0100628 INFO_MSG("Got CRTC: %d",num);
Rob Clark74210d52012-01-08 17:59:08 -0600629
Dave Barnish2742d152013-03-13 13:36:58 +0000630 // TODO: MIDEGL-1438: Potentially add code to allocate a HW cursor here.
Rob Clark74210d52012-01-08 17:59:08 -0600631
632 crtc->driver_private = drmmode_crtc;
633
634 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -0500635 return;
Rob Clark74210d52012-01-08 17:59:08 -0600636}
Rob Clark487687e2011-07-17 17:29:02 -0500637
638static xf86OutputStatus
639drmmode_output_detect(xf86OutputPtr output)
640{
641 /* go to the hw and retrieve a new output struct */
642 drmmode_output_private_ptr drmmode_output = output->driver_private;
643 drmmode_ptr drmmode = drmmode_output->drmmode;
644 xf86OutputStatus status;
645 drmModeFreeConnector(drmmode_output->mode_output);
646
647 drmmode_output->mode_output =
Rob Clark74210d52012-01-08 17:59:08 -0600648 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500649
650 switch (drmmode_output->mode_output->connection) {
651 case DRM_MODE_CONNECTED:
652 status = XF86OutputStatusConnected;
653 break;
654 case DRM_MODE_DISCONNECTED:
655 status = XF86OutputStatusDisconnected;
656 break;
657 default:
658 case DRM_MODE_UNKNOWNCONNECTION:
659 status = XF86OutputStatusUnknown;
660 break;
661 }
662 return status;
663}
664
665static Bool
666drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
667{
668 if (mode->type & M_T_DEFAULT)
669 /* Default modes are harmful here. */
670 return MODE_BAD;
671
672 return MODE_OK;
673}
674
675static DisplayModePtr
676drmmode_output_get_modes(xf86OutputPtr output)
677{
678 ScrnInfoPtr pScrn = output->scrn;
679 drmmode_output_private_ptr drmmode_output = output->driver_private;
680 drmModeConnectorPtr koutput = drmmode_output->mode_output;
681 drmmode_ptr drmmode = drmmode_output->drmmode;
682 DisplayModePtr Modes = NULL, Mode;
Daniel Kurtzb8131892012-10-17 01:39:54 +0800683 drmModePropertyPtr prop;
Rob Clark487687e2011-07-17 17:29:02 -0500684 xf86MonPtr ddc_mon = NULL;
685 int i;
686
687 /* look for an EDID property */
688 for (i = 0; i < koutput->count_props; i++) {
Daniel Kurtzb8131892012-10-17 01:39:54 +0800689 prop = drmModeGetProperty(drmmode->fd, koutput->props[i]);
690 if (!prop)
Rob Clark487687e2011-07-17 17:29:02 -0500691 continue;
692
Daniel Kurtzb8131892012-10-17 01:39:54 +0800693 if ((prop->flags & DRM_MODE_PROP_BLOB) &&
694 !strcmp(prop->name, "EDID")) {
Rob Clark487687e2011-07-17 17:29:02 -0500695 if (drmmode_output->edid_blob)
696 drmModeFreePropertyBlob(drmmode_output->edid_blob);
697 drmmode_output->edid_blob =
Rob Clark74210d52012-01-08 17:59:08 -0600698 drmModeGetPropertyBlob(drmmode->fd,
699 koutput->prop_values[i]);
Rob Clark487687e2011-07-17 17:29:02 -0500700 }
Daniel Kurtzb8131892012-10-17 01:39:54 +0800701 drmModeFreeProperty(prop);
Rob Clark487687e2011-07-17 17:29:02 -0500702 }
703
704 if (drmmode_output->edid_blob)
705 ddc_mon = xf86InterpretEDID(pScrn->scrnIndex,
Rob Clark74210d52012-01-08 17:59:08 -0600706 drmmode_output->edid_blob->data);
Rob Clark487687e2011-07-17 17:29:02 -0500707
708 if (ddc_mon) {
Rob Clark487687e2011-07-17 17:29:02 -0500709 xf86OutputSetEDID(output, ddc_mon);
710 xf86SetDDCproperties(pScrn, ddc_mon);
711 }
712
713 DEBUG_MSG("count_modes: %d", koutput->count_modes);
714
715 /* modes should already be available */
716 for (i = 0; i < koutput->count_modes; i++) {
717 Mode = xnfalloc(sizeof(DisplayModeRec));
718
719 drmmode_ConvertFromKMode(pScrn, &koutput->modes[i],
Rob Clark74210d52012-01-08 17:59:08 -0600720 Mode);
Rob Clark487687e2011-07-17 17:29:02 -0500721 Modes = xf86ModesAdd(Modes, Mode);
722
723 }
724 return Modes;
725}
726
727static void
728drmmode_output_destroy(xf86OutputPtr output)
729{
730 drmmode_output_private_ptr drmmode_output = output->driver_private;
731 int i;
732
733 if (drmmode_output->edid_blob)
734 drmModeFreePropertyBlob(drmmode_output->edid_blob);
735 for (i = 0; i < drmmode_output->num_props; i++) {
736 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
737 free(drmmode_output->props[i].atoms);
738 }
Daniel Kurtzf5a38ad2012-10-17 02:03:34 +0800739 free(drmmode_output->props);
Rob Clark487687e2011-07-17 17:29:02 -0500740 drmModeFreeConnector(drmmode_output->mode_output);
741 free(drmmode_output);
742 output->driver_private = NULL;
743}
744
745static void
746drmmode_output_dpms(xf86OutputPtr output, int mode)
747{
748 drmmode_output_private_ptr drmmode_output = output->driver_private;
749 drmModeConnectorPtr koutput = drmmode_output->mode_output;
Daniel Kurtzb8131892012-10-17 01:39:54 +0800750 drmModePropertyPtr prop;
Rob Clark487687e2011-07-17 17:29:02 -0500751 drmmode_ptr drmmode = drmmode_output->drmmode;
752 int mode_id = -1, i;
753
754 for (i = 0; i < koutput->count_props; i++) {
Daniel Kurtzb8131892012-10-17 01:39:54 +0800755 prop = drmModeGetProperty(drmmode->fd, koutput->props[i]);
756 if (!prop)
757 continue;
758 if ((prop->flags & DRM_MODE_PROP_ENUM) &&
759 !strcmp(prop->name, "DPMS")) {
760 mode_id = koutput->props[i];
761 drmModeFreeProperty(prop);
762 break;
Rob Clark487687e2011-07-17 17:29:02 -0500763 }
Daniel Kurtzb8131892012-10-17 01:39:54 +0800764 drmModeFreeProperty(prop);
Rob Clark487687e2011-07-17 17:29:02 -0500765 }
766
767 if (mode_id < 0)
768 return;
769
770 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
Rob Clark74210d52012-01-08 17:59:08 -0600771 mode_id, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500772}
773
774static Bool
775drmmode_property_ignore(drmModePropertyPtr prop)
776{
777 if (!prop)
Rob Clark74210d52012-01-08 17:59:08 -0600778 return TRUE;
Rob Clark487687e2011-07-17 17:29:02 -0500779 /* ignore blob prop */
780 if (prop->flags & DRM_MODE_PROP_BLOB)
781 return TRUE;
782 /* ignore standard property */
783 if (!strcmp(prop->name, "EDID") ||
Rob Clark74210d52012-01-08 17:59:08 -0600784 !strcmp(prop->name, "DPMS"))
Rob Clark487687e2011-07-17 17:29:02 -0500785 return TRUE;
786
787 return FALSE;
788}
789
790static void
791drmmode_output_create_resources(xf86OutputPtr output)
792{
793 drmmode_output_private_ptr drmmode_output = output->driver_private;
794 drmModeConnectorPtr mode_output = drmmode_output->mode_output;
795 drmmode_ptr drmmode = drmmode_output->drmmode;
796 drmModePropertyPtr drmmode_prop;
797 uint32_t value;
798 int i, j, err;
799
800 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
801 if (!drmmode_output->props)
802 return;
803
804 drmmode_output->num_props = 0;
805 for (i = 0, j = 0; i < mode_output->count_props; i++) {
806 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
807 if (drmmode_property_ignore(drmmode_prop)) {
808 drmModeFreeProperty(drmmode_prop);
809 continue;
810 }
811 drmmode_output->props[j].mode_prop = drmmode_prop;
812 drmmode_output->props[j].index = i;
813 drmmode_output->num_props++;
814 j++;
815 }
816
817 for (i = 0; i < drmmode_output->num_props; i++) {
818 drmmode_prop_ptr p = &drmmode_output->props[i];
819 drmmode_prop = p->mode_prop;
820
821 value = drmmode_output->mode_output->prop_values[p->index];
822
823 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
824 INT32 range[2];
825
826 p->num_atoms = 1;
827 p->atoms = calloc(p->num_atoms, sizeof(Atom));
828 if (!p->atoms)
829 continue;
830 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
831 range[0] = drmmode_prop->values[0];
832 range[1] = drmmode_prop->values[1];
833 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600834 FALSE, TRUE,
835 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
Rob Clark487687e2011-07-17 17:29:02 -0500836 2, range);
837 if (err != 0) {
838 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600839 "RRConfigureOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500840 }
841 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600842 XA_INTEGER, 32, PropModeReplace, 1,
843 &value, FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500844 if (err != 0) {
845 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600846 "RRChangeOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500847 }
848 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
849 p->num_atoms = drmmode_prop->count_enums + 1;
850 p->atoms = calloc(p->num_atoms, sizeof(Atom));
851 if (!p->atoms)
852 continue;
853 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
854 for (j = 1; j <= drmmode_prop->count_enums; j++) {
855 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
856 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
857 }
858 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600859 FALSE, FALSE,
860 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
Rob Clark487687e2011-07-17 17:29:02 -0500861 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
862 if (err != 0) {
863 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600864 "RRConfigureOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500865 }
866 for (j = 0; j < drmmode_prop->count_enums; j++)
867 if (drmmode_prop->enums[j].value == value)
868 break;
869 /* there's always a matching value */
870 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -0600871 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500872 if (err != 0) {
873 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600874 "RRChangeOutputProperty error, %d\n", err);
Rob Clark487687e2011-07-17 17:29:02 -0500875 }
876 }
877 }
878}
879
880static Bool
881drmmode_output_set_property(xf86OutputPtr output, Atom property,
Rob Clark74210d52012-01-08 17:59:08 -0600882 RRPropertyValuePtr value)
Rob Clark487687e2011-07-17 17:29:02 -0500883{
884 drmmode_output_private_ptr drmmode_output = output->driver_private;
885 drmmode_ptr drmmode = drmmode_output->drmmode;
886 int i, ret;
887
888 for (i = 0; i < drmmode_output->num_props; i++) {
889 drmmode_prop_ptr p = &drmmode_output->props[i];
890
891 if (p->atoms[0] != property)
892 continue;
893
894 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
895 uint32_t val;
896
897 if (value->type != XA_INTEGER || value->format != 32 ||
Rob Clark74210d52012-01-08 17:59:08 -0600898 value->size != 1)
Rob Clark487687e2011-07-17 17:29:02 -0500899 return FALSE;
900 val = *(uint32_t *)value->data;
901
902 ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
Rob Clark74210d52012-01-08 17:59:08 -0600903 p->mode_prop->prop_id, (uint64_t)val);
Rob Clark487687e2011-07-17 17:29:02 -0500904
905 if (ret)
906 return FALSE;
907
908 return TRUE;
909
910 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
911 Atom atom;
912 const char *name;
913 int j;
914
915 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
916 return FALSE;
917 memcpy(&atom, value->data, 4);
918 name = NameForAtom(atom);
919
920 /* search for matching name string, then set its value down */
921 for (j = 0; j < p->mode_prop->count_enums; j++) {
922 if (!strcmp(p->mode_prop->enums[j].name, name)) {
923 ret = drmModeConnectorSetProperty(drmmode->fd,
Rob Clark74210d52012-01-08 17:59:08 -0600924 drmmode_output->output_id,
925 p->mode_prop->prop_id,
926 p->mode_prop->enums[j].value);
Rob Clark487687e2011-07-17 17:29:02 -0500927
928 if (ret)
929 return FALSE;
930
931 return TRUE;
932 }
933 }
934
935 return FALSE;
936 }
937 }
938
939 return TRUE;
940}
941
942static Bool
943drmmode_output_get_property(xf86OutputPtr output, Atom property)
944{
945
946 drmmode_output_private_ptr drmmode_output = output->driver_private;
947 drmmode_ptr drmmode = drmmode_output->drmmode;
948 uint32_t value;
949 int err, i;
950
951 if (output->scrn->vtSema) {
952 drmModeFreeConnector(drmmode_output->mode_output);
953 drmmode_output->mode_output =
Rob Clark74210d52012-01-08 17:59:08 -0600954 drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500955 }
956
957 for (i = 0; i < drmmode_output->num_props; i++) {
958 drmmode_prop_ptr p = &drmmode_output->props[i];
959 if (p->atoms[0] != property)
960 continue;
961
962 value = drmmode_output->mode_output->prop_values[p->index];
963
964 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
965 err = RRChangeOutputProperty(output->randr_output,
Rob Clark74210d52012-01-08 17:59:08 -0600966 property, XA_INTEGER, 32,
967 PropModeReplace, 1, &value,
968 FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500969
970 return !err;
971 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
972 int j;
973
974 /* search for matching name string, then set its value down */
975 for (j = 0; j < p->mode_prop->count_enums; j++) {
976 if (p->mode_prop->enums[j].value == value)
977 break;
978 }
979
980 err = RRChangeOutputProperty(output->randr_output, property,
Rob Clark74210d52012-01-08 17:59:08 -0600981 XA_ATOM, 32, PropModeReplace, 1,
982 &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -0500983
984 return !err;
985 }
986 }
987
988 return FALSE;
989}
990
991static const xf86OutputFuncsRec drmmode_output_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600992 .create_resources = drmmode_output_create_resources,
993 .dpms = drmmode_output_dpms,
994 .detect = drmmode_output_detect,
995 .mode_valid = drmmode_output_mode_valid,
996 .get_modes = drmmode_output_get_modes,
997 .set_property = drmmode_output_set_property,
998 .get_property = drmmode_output_get_property,
999 .destroy = drmmode_output_destroy
Rob Clark487687e2011-07-17 17:29:02 -05001000};
1001
Rob Clark487687e2011-07-17 17:29:02 -05001002const char *output_names[] = { "None",
Rob Clark74210d52012-01-08 17:59:08 -06001003 "VGA",
1004 "DVI-I",
1005 "DVI-D",
1006 "DVI-A",
1007 "Composite",
1008 "SVIDEO",
1009 "LVDS",
1010 "CTV",
1011 "DIN",
1012 "DP",
1013 "HDMI",
1014 "HDMI",
1015 "TV",
1016 "eDP",
Rob Clark487687e2011-07-17 17:29:02 -05001017};
1018#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
1019
1020static void
1021drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
1022{
Rob Clark74210d52012-01-08 17:59:08 -06001023 xf86OutputPtr output;
1024 drmModeConnectorPtr koutput;
1025 drmModeEncoderPtr kencoder;
1026 drmmode_output_private_ptr drmmode_output;
1027 char name[32];
Rob Clark487687e2011-07-17 17:29:02 -05001028
Rob Clark74210d52012-01-08 17:59:08 -06001029 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001030
Rob Clark74210d52012-01-08 17:59:08 -06001031 koutput = drmModeGetConnector(drmmode->fd,
1032 drmmode->mode_res->connectors[num]);
1033 if (!koutput)
1034 return;
Rob Clark487687e2011-07-17 17:29:02 -05001035
Rob Clark74210d52012-01-08 17:59:08 -06001036 kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
1037 if (!kencoder) {
1038 drmModeFreeConnector(koutput);
1039 return;
1040 }
Rob Clark487687e2011-07-17 17:29:02 -05001041
Rob Clark74210d52012-01-08 17:59:08 -06001042 if (koutput->connector_type >= NUM_OUTPUT_NAMES)
1043 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
1044 koutput->connector_type_id);
1045 else
1046 snprintf(name, 32, "%s-%d",
1047 output_names[koutput->connector_type],
1048 koutput->connector_type_id);
Rob Clark487687e2011-07-17 17:29:02 -05001049
Rob Clark74210d52012-01-08 17:59:08 -06001050 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
1051 if (!output) {
1052 drmModeFreeEncoder(kencoder);
1053 drmModeFreeConnector(koutput);
1054 return;
1055 }
Rob Clark487687e2011-07-17 17:29:02 -05001056
Rob Clark74210d52012-01-08 17:59:08 -06001057 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
1058 if (!drmmode_output) {
1059 xf86OutputDestroy(output);
1060 drmModeFreeConnector(koutput);
1061 drmModeFreeEncoder(kencoder);
1062 return;
1063 }
Rob Clark487687e2011-07-17 17:29:02 -05001064
Rob Clark74210d52012-01-08 17:59:08 -06001065 drmmode_output->output_id = drmmode->mode_res->connectors[num];
1066 drmmode_output->mode_output = koutput;
1067 drmmode_output->mode_encoder = kencoder;
1068 drmmode_output->drmmode = drmmode;
Rob Clark487687e2011-07-17 17:29:02 -05001069
Rob Clark74210d52012-01-08 17:59:08 -06001070 output->mm_width = koutput->mmWidth;
1071 output->mm_height = koutput->mmHeight;
1072 output->driver_private = drmmode_output;
Rob Clark487687e2011-07-17 17:29:02 -05001073
Dave Barnishf0952c12013-05-10 15:52:23 +01001074 if (ARMSOCPTR(pScrn)->crtcNum >= 0) {
1075 /* Only single crtc per screen - see if this output can use it*/
1076 output->possible_crtcs =
1077 (kencoder->possible_crtcs>>(ARMSOCPTR(pScrn)->crtcNum))&1;
1078 } else {
1079 output->possible_crtcs = kencoder->possible_crtcs;
1080 }
1081
Rob Clark74210d52012-01-08 17:59:08 -06001082 output->possible_clones = kencoder->possible_clones;
1083 output->interlaceAllowed = TRUE;
Rob Clark487687e2011-07-17 17:29:02 -05001084
Rob Clark74210d52012-01-08 17:59:08 -06001085 TRACE_EXIT();
1086 return;
1087}
Rob Clark487687e2011-07-17 17:29:02 -05001088
Paul Geary8ffd91c2013-04-11 16:03:15 +01001089void set_scanout_bo(ScrnInfoPtr pScrn, struct armsoc_bo *bo)
David Garbett3688b332012-05-11 12:17:34 +01001090{
Paul Geary8ffd91c2013-04-11 16:03:15 +01001091 ARMSOCPtr pARMSOC = ARMSOCPTR(pScrn);
David Garbett3688b332012-05-11 12:17:34 +01001092
1093 /* It had better have a framebuffer if we're scanning it out */
Paul Geary8ffd91c2013-04-11 16:03:15 +01001094 assert(armsoc_bo_get_fb(bo));
David Garbett3688b332012-05-11 12:17:34 +01001095
Paul Geary8ffd91c2013-04-11 16:03:15 +01001096 pARMSOC->scanout = bo;
David Garbett3688b332012-05-11 12:17:34 +01001097}
1098
Rob Clark487687e2011-07-17 17:29:02 -05001099static Bool
1100drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
1101{
Paul Geary8ffd91c2013-04-11 16:03:15 +01001102 ARMSOCPtr pARMSOC = ARMSOCPTR(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001103 ScreenPtr pScreen = pScrn->pScreen;
Sean Paul3e107302012-08-30 12:08:12 -07001104 uint32_t pitch;
Brian Starkeycd684422012-09-20 09:28:04 +01001105 int i;
1106 xf86CrtcConfigPtr xf86_config;
Rob Clark487687e2011-07-17 17:29:02 -05001107
1108 TRACE_ENTER();
Dave Barnish33866052013-03-18 10:57:40 +00001109 DEBUG_MSG("Resize: %dx%d", width, height);
Rob Clark487687e2011-07-17 17:29:02 -05001110
1111 pScrn->virtualX = width;
1112 pScrn->virtualY = height;
1113
Paul Geary8ffd91c2013-04-11 16:03:15 +01001114 if ( (width != armsoc_bo_width(pARMSOC->scanout))
1115 || (height != armsoc_bo_height(pARMSOC->scanout))
1116 || (pScrn->bitsPerPixel != armsoc_bo_bpp(pARMSOC->scanout)) ) {
Dave Barnish33866052013-03-18 10:57:40 +00001117 struct armsoc_bo *new_scanout;
Rob Clark487687e2011-07-17 17:29:02 -05001118
1119 /* allocate new scanout buffer */
Dave Barnish33866052013-03-18 10:57:40 +00001120 new_scanout = armsoc_bo_new_with_dim(pARMSOC->dev, width, height, pScrn->depth, pScrn->bitsPerPixel, ARMSOC_BO_SCANOUT );
1121 if (!new_scanout)
David Garbettae5a6362012-07-02 10:15:47 +01001122 {
Dave Barnish33866052013-03-18 10:57:40 +00001123 /* Try to use the previous buffer if the new resolution is smaller than the one on buffer creation */
1124 DEBUG_MSG("allocate new scanout buffer failed - resizing existing bo");
1125 /* Remove the old fb from the bo */
1126 if( armsoc_bo_rm_fb( pARMSOC->scanout ) )
1127 {
1128 return FALSE;
1129 }
1130 /* Resize the bo */
1131 if ( armsoc_bo_resize(pARMSOC->scanout, width, height) )
1132 {
1133 armsoc_bo_clear(pARMSOC->scanout);
1134 armsoc_bo_add_fb(pARMSOC->scanout);
1135 return FALSE;
1136 }
1137 /* Add new fb to the bo */
1138 if( armsoc_bo_clear(pARMSOC->scanout) || armsoc_bo_add_fb(pARMSOC->scanout) )
1139 {
1140 return FALSE;
1141 }
1142 pitch = armsoc_bo_pitch(pARMSOC->scanout);
1143 }
1144 else
1145 {
1146 DEBUG_MSG("allocated new scanout buffer okay");
1147 pitch = armsoc_bo_pitch(new_scanout);
1148 /* clear new BO and add FB */
1149 if (armsoc_bo_clear(new_scanout) || armsoc_bo_add_fb(new_scanout))
1150 {
Paul Geary8ffd91c2013-04-11 16:03:15 +01001151 armsoc_bo_unreference(new_scanout);
David Garbettae5a6362012-07-02 10:15:47 +01001152 return FALSE;
1153 }
Dave Barnish33866052013-03-18 10:57:40 +00001154 /* Handle dma_buf fd that may be attached to old bo */
1155 if(armsoc_bo_has_dmabuf(pARMSOC->scanout))
1156 {
1157 int res;
1158
1159 armsoc_bo_clear_dmabuf(pARMSOC->scanout);
1160 res = armsoc_bo_set_dmabuf(new_scanout);
1161 if(res) {
1162 ERROR_MSG("Unable to attach dma_buf fd to new scanout buffer - %d (%s)\n", res, strerror(res));
1163 armsoc_bo_unreference(new_scanout);
1164 return FALSE;
1165 }
1166 }
1167 /* delete old scanout buffer */
1168 armsoc_bo_unreference(pARMSOC->scanout);
1169 /* use new scanout buffer */
1170 set_scanout_bo(pScrn, new_scanout);
David Garbettae5a6362012-07-02 10:15:47 +01001171 }
Dave Barnish33866052013-03-18 10:57:40 +00001172 pARMSOC->has_resized = TRUE;
Daniel Kurtz34e72b02012-10-19 14:02:05 -07001173 pScrn->displayWidth = pitch / ((pScrn->bitsPerPixel + 7) / 8);
Dave Barnish33866052013-03-18 10:57:40 +00001174 }
1175 else
1176 {
Paul Geary8ffd91c2013-04-11 16:03:15 +01001177 pitch = armsoc_bo_pitch(pARMSOC->scanout);
Rob Clark487687e2011-07-17 17:29:02 -05001178 }
1179
1180 if (pScreen && pScreen->ModifyPixmapHeader) {
1181 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
Dave Barnish33866052013-03-18 10:57:40 +00001182
Rob Clark487687e2011-07-17 17:29:02 -05001183 pScreen->ModifyPixmapHeader(rootPixmap,
1184 pScrn->virtualX, pScrn->virtualY,
1185 pScrn->depth, pScrn->bitsPerPixel, pitch,
Paul Geary8ffd91c2013-04-11 16:03:15 +01001186 armsoc_bo_map(pARMSOC->scanout));
Rob Clark487687e2011-07-17 17:29:02 -05001187 }
1188
Brian Starkeycd684422012-09-20 09:28:04 +01001189 /* Framebuffer needs to be reset on all CRTCs, not just
1190 * those that have repositioned */
1191 xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1192 for (i = 0; i < xf86_config->num_crtc; i++) {
1193 xf86CrtcPtr crtc = xf86_config->crtc[i];
1194
1195 if (!crtc->enabled)
1196 continue;
1197
1198 drmmode_set_mode_major(crtc, &crtc->mode,
1199 crtc->rotation, crtc->x, crtc->y);
1200 }
1201
Rob Clark487687e2011-07-17 17:29:02 -05001202 TRACE_EXIT();
1203 return TRUE;
Rob Clark74210d52012-01-08 17:59:08 -06001204}
Rob Clark487687e2011-07-17 17:29:02 -05001205
1206static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -06001207 drmmode_xf86crtc_resize
Rob Clark487687e2011-07-17 17:29:02 -05001208};
1209
1210
1211Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
1212{
Rob Clark74210d52012-01-08 17:59:08 -06001213 drmmode_ptr drmmode;
1214 int i;
Rob Clark487687e2011-07-17 17:29:02 -05001215
Rob Clark74210d52012-01-08 17:59:08 -06001216 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001217
Rob Clark74210d52012-01-08 17:59:08 -06001218 drmmode = calloc(1, sizeof *drmmode);
Paul Geary6fe52f32013-04-03 11:12:24 +01001219 if(!drmmode) {
1220 return FALSE;
1221 }
1222
Rob Clark74210d52012-01-08 17:59:08 -06001223 drmmode->fd = fd;
Rob Clark487687e2011-07-17 17:29:02 -05001224
Rob Clark74210d52012-01-08 17:59:08 -06001225 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
Rob Clark487687e2011-07-17 17:29:02 -05001226
1227
Rob Clark74210d52012-01-08 17:59:08 -06001228 drmmode->cpp = cpp;
1229 drmmode->mode_res = drmModeGetResources(drmmode->fd);
1230 if (!drmmode->mode_res) {
Paul Geary6fe52f32013-04-03 11:12:24 +01001231 free(drmmode);
Rob Clark74210d52012-01-08 17:59:08 -06001232 return FALSE;
1233 } else {
1234 DEBUG_MSG("Got KMS resources");
1235 DEBUG_MSG(" %d connectors, %d encoders",
1236 drmmode->mode_res->count_connectors,
1237 drmmode->mode_res->count_encoders);
1238 DEBUG_MSG(" %d crtcs, %d fbs",
1239 drmmode->mode_res->count_crtcs, drmmode->mode_res->count_fbs);
1240 DEBUG_MSG(" %dx%d minimum resolution",
1241 drmmode->mode_res->min_width, drmmode->mode_res->min_height);
1242 DEBUG_MSG(" %dx%d maximum resolution",
1243 drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1244 }
1245 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
1246 drmmode->mode_res->max_height);
Dave Barnishf0952c12013-05-10 15:52:23 +01001247
1248 if(ARMSOCPTR(pScrn)->crtcNum == -1) {
1249 INFO_MSG("Adding all CRTCs");
1250 for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1251 drmmode_crtc_init(pScrn, drmmode, i);
1252 }else if(ARMSOCPTR(pScrn)->crtcNum < drmmode->mode_res->count_crtcs) {
1253 drmmode_crtc_init(pScrn, drmmode, ARMSOCPTR(pScrn)->crtcNum);
1254 } else {
1255 ERROR_MSG("Specified more Screens in xorg.conf than there are DRM CRTCs");
1256 return FALSE;
1257 }
Rob Clark487687e2011-07-17 17:29:02 -05001258
Rob Clark74210d52012-01-08 17:59:08 -06001259 for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1260 drmmode_output_init(pScrn, drmmode, i);
Rob Clark487687e2011-07-17 17:29:02 -05001261
Rob Clark74210d52012-01-08 17:59:08 -06001262 xf86InitialConfiguration(pScrn, TRUE);
Rob Clark487687e2011-07-17 17:29:02 -05001263
Rob Clark74210d52012-01-08 17:59:08 -06001264 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -05001265
Rob Clark74210d52012-01-08 17:59:08 -06001266 return TRUE;
1267}
Rob Clark487687e2011-07-17 17:29:02 -05001268
1269void
Cooper Yuana83caa62012-06-28 17:19:06 +02001270drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y)
Rob Clark487687e2011-07-17 17:29:02 -05001271{
1272 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1273 xf86OutputPtr output = config->output[config->compat_output];
1274 xf86CrtcPtr crtc = output->crtc;
1275
1276 if (!crtc || !crtc->enabled)
1277 return;
1278
1279 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
1280}
1281
Rob Clark4b8f30a2011-08-28 12:51:26 -05001282/*
1283 * Page Flipping
1284 */
1285
1286static void
1287page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
Rob Clark74210d52012-01-08 17:59:08 -06001288 unsigned int tv_usec, void *user_data)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001289{
Paul Geary8ffd91c2013-04-11 16:03:15 +01001290 ARMSOCDRI2SwapComplete(user_data);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001291}
1292
1293static drmEventContext event_context = {
1294 .version = DRM_EVENT_CONTEXT_VERSION,
1295 .page_flip_handler = page_flip_handler,
1296};
1297
John Sheu022833e2012-08-15 11:40:11 -07001298int
Rob Clark4b8f30a2011-08-28 12:51:26 -05001299drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
1300{
Ray Smith3c33c3d2013-03-26 16:06:37 +00001301 ScrnInfoPtr pScrn = xf86Screens[draw->pScreen->myNum];
Paul Geary8ffd91c2013-04-11 16:03:15 +01001302 ARMSOCPtr pARMSOC = ARMSOCPTR(pScrn);
Ray Smith3c33c3d2013-03-26 16:06:37 +00001303 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001304 drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
1305 drmmode_ptr mode = crtc->drmmode;
John Sheu022833e2012-08-15 11:40:11 -07001306 int ret, i, failed = 0, num_flipped = 0;
Raymond Smith16a910e2012-05-09 13:04:51 +01001307 unsigned int flags = 0;
1308
Paul Geary8ffd91c2013-04-11 16:03:15 +01001309 if (pARMSOC->drmmode->use_page_flip_events)
Ray Smith3c33c3d2013-03-26 16:06:37 +00001310 flags |= DRM_MODE_PAGE_FLIP_EVENT;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001311
1312 /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
1313 for (i = 0; i < config->num_crtc; i++) {
1314 crtc = config->crtc[i]->driver_private;
1315
Ray Smithe20b3812013-04-08 12:53:53 +01001316 if (!config->crtc[i]->enabled)
1317 continue;
1318
Rob Clark4b8f30a2011-08-28 12:51:26 -05001319 ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
Raymond Smith16a910e2012-05-09 13:04:51 +01001320 fb_id, flags, priv);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001321 if (ret) {
Ray Smith3c33c3d2013-03-26 16:06:37 +00001322 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
Rob Clark74210d52012-01-08 17:59:08 -06001323 "flip queue failed: %s\n", strerror(errno));
John Sheu022833e2012-08-15 11:40:11 -07001324 failed = 1;
1325 }
1326 else {
1327 num_flipped += 1;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001328 }
1329 }
1330
John Sheu022833e2012-08-15 11:40:11 -07001331 if (failed)
1332 return -(num_flipped + 1);
1333 else
1334 return num_flipped;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001335}
Rob Clark487687e2011-07-17 17:29:02 -05001336
1337/*
1338 * Hot Plug Event handling:
1339 */
1340
Rob Clark487687e2011-07-17 17:29:02 -05001341static void
1342drmmode_handle_uevents(int fd, void *closure)
1343{
Rob Clark74210d52012-01-08 17:59:08 -06001344 ScrnInfoPtr pScrn = closure;
Paul Geary8ffd91c2013-04-11 16:03:15 +01001345 ARMSOCPtr pARMSOC = ARMSOCPTR(pScrn);
Rob Clark74210d52012-01-08 17:59:08 -06001346 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1347 struct udev_device *dev;
1348 const char *hotplug;
1349 struct stat s;
1350 dev_t udev_devnum;
Rob Clark487687e2011-07-17 17:29:02 -05001351
Rob Clark74210d52012-01-08 17:59:08 -06001352 dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1353 if (!dev)
1354 return;
Rob Clark487687e2011-07-17 17:29:02 -05001355
Dave Barnish2742d152013-03-13 13:36:58 +00001356 // TODO: MIDEGL-1441: Do we need to keep this code, which Rob originally wrote
Rob Clark74210d52012-01-08 17:59:08 -06001357 // (i.e. up thru the "if" statement)?:
Rob Clark487687e2011-07-17 17:29:02 -05001358
Rob Clark74210d52012-01-08 17:59:08 -06001359 /*
1360 * Check to make sure this event is directed at our
1361 * device (by comparing dev_t values), then make
1362 * sure it's a hotplug event (HOTPLUG=1)
1363 */
1364 udev_devnum = udev_device_get_devnum(dev);
Paul Geary8ffd91c2013-04-11 16:03:15 +01001365 fstat(pARMSOC->drmFD, &s);
Rob Clark487687e2011-07-17 17:29:02 -05001366
Rob Clark74210d52012-01-08 17:59:08 -06001367 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
Rob Clark487687e2011-07-17 17:29:02 -05001368
Rob Clark74210d52012-01-08 17:59:08 -06001369 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug,
Daniel Kurtz926fd1e2012-11-10 12:20:35 +08001370 !memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)));
Rob Clark487687e2011-07-17 17:29:02 -05001371
Rob Clark74210d52012-01-08 17:59:08 -06001372 if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
1373 hotplug && atoi(hotplug) == 1) {
1374 RRGetInfo(screenInfo.screens[pScrn->scrnIndex], TRUE);
1375 }
1376 udev_device_unref(dev);
1377}
Rob Clark487687e2011-07-17 17:29:02 -05001378
Rob Clark4b8f30a2011-08-28 12:51:26 -05001379static void
Rob Clark487687e2011-07-17 17:29:02 -05001380drmmode_uevent_init(ScrnInfoPtr pScrn)
1381{
Rob Clark74210d52012-01-08 17:59:08 -06001382 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1383 struct udev *u;
1384 struct udev_monitor *mon;
Rob Clark487687e2011-07-17 17:29:02 -05001385
Rob Clark74210d52012-01-08 17:59:08 -06001386 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001387
Rob Clark74210d52012-01-08 17:59:08 -06001388 u = udev_new();
1389 if (!u)
1390 return;
1391 mon = udev_monitor_new_from_netlink(u, "udev");
1392 if (!mon) {
1393 udev_unref(u);
1394 return;
1395 }
Rob Clark487687e2011-07-17 17:29:02 -05001396
Rob Clark74210d52012-01-08 17:59:08 -06001397 if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1398 "drm",
1399 "drm_minor") < 0 ||
1400 udev_monitor_enable_receiving(mon) < 0) {
1401 udev_monitor_unref(mon);
1402 udev_unref(u);
1403 return;
1404 }
Rob Clark487687e2011-07-17 17:29:02 -05001405
Rob Clark74210d52012-01-08 17:59:08 -06001406 drmmode->uevent_handler =
1407 xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1408 drmmode_handle_uevents, pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001409
Rob Clark74210d52012-01-08 17:59:08 -06001410 drmmode->uevent_monitor = mon;
Rob Clark487687e2011-07-17 17:29:02 -05001411
Rob Clark74210d52012-01-08 17:59:08 -06001412 TRACE_EXIT();
1413}
Rob Clark487687e2011-07-17 17:29:02 -05001414
Rob Clark4b8f30a2011-08-28 12:51:26 -05001415static void
Rob Clark487687e2011-07-17 17:29:02 -05001416drmmode_uevent_fini(ScrnInfoPtr pScrn)
1417{
Rob Clark74210d52012-01-08 17:59:08 -06001418 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001419
Rob Clark74210d52012-01-08 17:59:08 -06001420 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001421
Rob Clark74210d52012-01-08 17:59:08 -06001422 if (drmmode->uevent_handler) {
1423 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1424 xf86RemoveGeneralHandler(drmmode->uevent_handler);
Rob Clark487687e2011-07-17 17:29:02 -05001425
Rob Clark74210d52012-01-08 17:59:08 -06001426 udev_monitor_unref(drmmode->uevent_monitor);
1427 udev_unref(u);
1428 }
Rob Clark487687e2011-07-17 17:29:02 -05001429
Rob Clark74210d52012-01-08 17:59:08 -06001430 TRACE_EXIT();
1431}
Rob Clark4b8f30a2011-08-28 12:51:26 -05001432
1433static void
1434drmmode_wakeup_handler(pointer data, int err, pointer p)
1435{
Rob Clark67b875f2012-04-20 19:13:57 -05001436 ScrnInfoPtr pScrn = data;
Paul Geary6fe52f32013-04-03 11:12:24 +01001437 drmmode_ptr drmmode;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001438 fd_set *read_mask = p;
1439
Rob Clark67b875f2012-04-20 19:13:57 -05001440 if (pScrn == NULL || err < 0)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001441 return;
1442
Paul Geary6fe52f32013-04-03 11:12:24 +01001443 drmmode = drmmode_from_scrn(pScrn);
1444
Rob Clark4b8f30a2011-08-28 12:51:26 -05001445 if (FD_ISSET(drmmode->fd, read_mask))
1446 drmHandleEvent(drmmode->fd, &event_context);
1447}
1448
1449void
Rob Clark67b875f2012-04-20 19:13:57 -05001450drmmode_wait_for_event(ScrnInfoPtr pScrn)
1451{
1452 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
1453 drmHandleEvent(drmmode->fd, &event_context);
1454}
1455
1456void
Rob Clark4b8f30a2011-08-28 12:51:26 -05001457drmmode_screen_init(ScrnInfoPtr pScrn)
1458{
Rob Clark74210d52012-01-08 17:59:08 -06001459 drmmode_ptr drmmode = drmmode_from_scrn(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001460
1461 drmmode_uevent_init(pScrn);
1462
Rob Clark74210d52012-01-08 17:59:08 -06001463 AddGeneralSocket(drmmode->fd);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001464
Rob Clark74210d52012-01-08 17:59:08 -06001465 /* Register a wakeup handler to get informed on DRM events */
1466 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1467 drmmode_wakeup_handler, pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001468}
1469
1470void
1471drmmode_screen_fini(ScrnInfoPtr pScrn)
1472{
1473 drmmode_uevent_fini(pScrn);
1474}