1 /*
2 * Copyright © 2007 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Dave Airlie <airlied@redhat.com>
25 *
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/poll.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <sys/ioctl.h>
39
40 #include "xorg-server.h"
41 #include "xorgVersion.h"
42
43 #include "intel.h"
44 #include "intel_bufmgr.h"
45 #include "intel_options.h"
46 #include "backlight.h"
47 #include "xf86drm.h"
48 #include "xf86drmMode.h"
49 #include "X11/Xatom.h"
50 #if defined(HAVE_X11_EXTENSIONS_DPMSCONST_H)
51 #include <X11/extensions/dpmsconst.h>
52 #else
53 #define DPMSModeOn 0
54 #define DPMSModeOff 3
55 #endif
56 #include "xf86DDC.h"
57 #include "fb.h"
58
59 #if USE_UXA
60 #include "intel_uxa.h"
61 #endif
62
63 #define KNOWN_MODE_FLAGS ((1<<14)-1)
64
65 struct intel_drm_queue {
66 struct list list;
67 xf86CrtcPtr crtc;
68 uint32_t seq;
69 void *data;
70 ScrnInfoPtr scrn;
71 intel_drm_handler_proc handler;
72 intel_drm_abort_proc abort;
73 };
74
75 static uint32_t intel_drm_seq;
76 static struct list intel_drm_queue;
77
78 struct intel_mode {
79 int fd;
80 uint32_t fb_id;
81 int cpp;
82
83 drmEventContext event_context;
84 int old_fb_id;
85 int flip_count;
86 uint64_t fe_msc;
87 uint64_t fe_usec;
88
89 struct list outputs;
90 struct list crtcs;
91
92 struct {
93 intel_pageflip_handler_proc handler;
94 intel_pageflip_abort_proc abort;
95 void *data;
96 } pageflip;
97 };
98
99 struct intel_pageflip {
100 struct intel_mode *mode;
101 Bool dispatch_me;
102 };
103
104 struct intel_crtc {
105 struct intel_mode *mode;
106 drmModeModeInfo kmode;
107 drmModeCrtcPtr mode_crtc;
108 int pipe;
109 dri_bo *cursor;
110 dri_bo *rotate_bo;
111 uint32_t rotate_pitch;
112 uint32_t rotate_fb_id;
113 xf86CrtcPtr crtc;
114 struct list link;
115 PixmapPtr scanout_pixmap;
116 uint32_t scanout_fb_id;
117 uint32_t msc_prev;
118 uint64_t msc_high;
119 };
120
121 struct intel_property {
122 drmModePropertyPtr mode_prop;
123 uint64_t value;
124 int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */
125 Atom *atoms;
126 };
127
128 struct intel_output {
129 struct intel_mode *mode;
130 int output_id;
131 drmModeConnectorPtr mode_output;
132 drmModeEncoderPtr *mode_encoders;
133 drmModePropertyBlobPtr edid_blob;
134 int num_props;
135 struct intel_property *props;
136 void *private_data;
137
138 Bool has_panel_limits;
139 int panel_hdisplay;
140 int panel_vdisplay;
141
142 int dpms_mode;
143 struct backlight backlight;
144 int backlight_active_level;
145 xf86OutputPtr output;
146 struct list link;
147 int enc_mask;
148 int enc_clone_mask;
149 };
150
151 static void
152 intel_output_dpms(xf86OutputPtr output, int mode);
153
154 static void
155 intel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode);
156
157 static inline int
crtc_id(struct intel_crtc * crtc)158 crtc_id(struct intel_crtc *crtc)
159 {
160 return crtc->mode_crtc->crtc_id;
161 }
162
163 static void
intel_output_backlight_set(xf86OutputPtr output,int level)164 intel_output_backlight_set(xf86OutputPtr output, int level)
165 {
166 struct intel_output *intel_output = output->driver_private;
167 if (backlight_set(&intel_output->backlight, level) < 0) {
168 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
169 "failed to set backlight %s to brightness level %d, disabling\n",
170 intel_output->backlight.iface, level);
171 backlight_disable(&intel_output->backlight);
172 }
173 }
174
175 static int
intel_output_backlight_get(xf86OutputPtr output)176 intel_output_backlight_get(xf86OutputPtr output)
177 {
178 struct intel_output *intel_output = output->driver_private;
179 return backlight_get(&intel_output->backlight);
180 }
181
182 static void
intel_output_backlight_init(xf86OutputPtr output)183 intel_output_backlight_init(xf86OutputPtr output)
184 {
185 struct intel_output *intel_output = output->driver_private;
186 intel_screen_private *intel = intel_get_screen_private(output->scrn);
187 const char *str;
188
189 #if !USE_BACKLIGHT
190 return;
191 #endif
192
193 str = xf86GetOptValString(intel->Options, OPTION_BACKLIGHT);
194 if (str != NULL) {
195 if (backlight_exists(str)) {
196 intel_output->backlight_active_level =
197 backlight_open(&intel_output->backlight,
198 strdup(str));
199 if (intel_output->backlight_active_level != -1) {
200 xf86DrvMsg(output->scrn->scrnIndex, X_CONFIG,
201 "found backlight control interface %s\n", str);
202 return;
203 }
204 }
205
206 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
207 "unrecognised backlight control interface %s\n", str);
208 }
209
210 intel_output->backlight_active_level =
211 backlight_open(&intel_output->backlight, NULL);
212 if (intel_output->backlight_active_level != -1) {
213 xf86DrvMsg(output->scrn->scrnIndex, X_PROBED,
214 "found backlight control interface %s\n",
215 intel_output->backlight.iface);
216 return;
217 }
218 }
219
220 static void
mode_from_kmode(ScrnInfoPtr scrn,drmModeModeInfoPtr kmode,DisplayModePtr mode)221 mode_from_kmode(ScrnInfoPtr scrn,
222 drmModeModeInfoPtr kmode,
223 DisplayModePtr mode)
224 {
225 memset(mode, 0, sizeof(DisplayModeRec));
226 mode->status = MODE_OK;
227
228 mode->Clock = kmode->clock;
229
230 mode->HDisplay = kmode->hdisplay;
231 mode->HSyncStart = kmode->hsync_start;
232 mode->HSyncEnd = kmode->hsync_end;
233 mode->HTotal = kmode->htotal;
234 mode->HSkew = kmode->hskew;
235
236 mode->VDisplay = kmode->vdisplay;
237 mode->VSyncStart = kmode->vsync_start;
238 mode->VSyncEnd = kmode->vsync_end;
239 mode->VTotal = kmode->vtotal;
240 mode->VScan = kmode->vscan;
241
242 mode->Flags = kmode->flags;
243 mode->name = strdup(kmode->name);
244
245 if (kmode->type & DRM_MODE_TYPE_DRIVER)
246 mode->type = M_T_DRIVER;
247 if (kmode->type & DRM_MODE_TYPE_PREFERRED)
248 mode->type |= M_T_PREFERRED;
249
250 if (mode->status == MODE_OK && kmode->flags & ~KNOWN_MODE_FLAGS)
251 mode->status = MODE_BAD; /* unknown flags => unhandled */
252
253 xf86SetModeCrtc (mode, scrn->adjustFlags);
254 }
255
256 static void
mode_to_kmode(ScrnInfoPtr scrn,drmModeModeInfoPtr kmode,DisplayModePtr mode)257 mode_to_kmode(ScrnInfoPtr scrn,
258 drmModeModeInfoPtr kmode,
259 DisplayModePtr mode)
260 {
261 memset(kmode, 0, sizeof(*kmode));
262
263 kmode->clock = mode->Clock;
264 kmode->hdisplay = mode->HDisplay;
265 kmode->hsync_start = mode->HSyncStart;
266 kmode->hsync_end = mode->HSyncEnd;
267 kmode->htotal = mode->HTotal;
268 kmode->hskew = mode->HSkew;
269
270 kmode->vdisplay = mode->VDisplay;
271 kmode->vsync_start = mode->VSyncStart;
272 kmode->vsync_end = mode->VSyncEnd;
273 kmode->vtotal = mode->VTotal;
274 kmode->vscan = mode->VScan;
275
276 kmode->flags = mode->Flags;
277 if (mode->name)
278 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
279 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
280 }
281
282 static void
intel_crtc_dpms(xf86CrtcPtr crtc,int mode)283 intel_crtc_dpms(xf86CrtcPtr crtc, int mode)
284 {
285 }
286
287 void
intel_mode_disable_unused_functions(ScrnInfoPtr scrn)288 intel_mode_disable_unused_functions(ScrnInfoPtr scrn)
289 {
290 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
291 struct intel_mode *mode = intel_get_screen_private(scrn)->modes;
292 int i;
293
294 /* Force off for consistency between kernel and ddx */
295 for (i = 0; i < xf86_config->num_crtc; i++) {
296 xf86CrtcPtr crtc = xf86_config->crtc[i];
297 if (!crtc->enabled)
298 drmModeSetCrtc(mode->fd, crtc_id(crtc->driver_private),
299 0, 0, 0, NULL, 0, NULL);
300 }
301 }
302
303 static Bool
intel_crtc_apply(xf86CrtcPtr crtc)304 intel_crtc_apply(xf86CrtcPtr crtc)
305 {
306 ScrnInfoPtr scrn = crtc->scrn;
307 struct intel_crtc *intel_crtc = crtc->driver_private;
308 struct intel_mode *mode = intel_crtc->mode;
309 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
310 uint32_t *output_ids;
311 int output_count = 0;
312 int fb_id, x, y;
313 int i, ret = FALSE;
314
315 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
316 if (!output_ids)
317 return FALSE;
318
319 for (i = 0; i < xf86_config->num_output; i++) {
320 xf86OutputPtr output = xf86_config->output[i];
321 struct intel_output *intel_output;
322
323 /* Make sure we mark the output as off (and save the backlight)
324 * before the kernel turns it off due to changing the pipe.
325 * This is necessary as the kernel may turn off the backlight
326 * and we lose track of the user settings.
327 */
328 if (output->crtc == NULL)
329 output->funcs->dpms(output, DPMSModeOff);
330
331 if (output->crtc != crtc)
332 continue;
333
334 intel_output = output->driver_private;
335 if (!intel_output->mode_output)
336 return FALSE;
337
338 output_ids[output_count] =
339 intel_output->mode_output->connector_id;
340 output_count++;
341 }
342
343 if (!intel_crtc->scanout_fb_id) {
344 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0)
345 if (!xf86CrtcRotate(crtc, mode, rotation))
346 goto done;
347 #else
348 if (!xf86CrtcRotate(crtc))
349 goto done;
350 #endif
351 }
352
353 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0)
354 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
355 crtc->gamma_blue, crtc->gamma_size);
356 #endif
357
358 x = crtc->x;
359 y = crtc->y;
360 fb_id = mode->fb_id;
361 if (intel_crtc->rotate_fb_id) {
362 fb_id = intel_crtc->rotate_fb_id;
363 x = 0;
364 y = 0;
365 } else if (intel_crtc->scanout_fb_id && intel_crtc->scanout_pixmap->drawable.width >= crtc->mode.HDisplay && intel_crtc->scanout_pixmap->drawable.height >= crtc->mode.VDisplay) {
366 fb_id = intel_crtc->scanout_fb_id;
367 x = 0;
368 y = 0;
369 }
370 ret = drmModeSetCrtc(mode->fd, crtc_id(intel_crtc),
371 fb_id, x, y, output_ids, output_count,
372 &intel_crtc->kmode);
373 if (ret) {
374 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
375 "failed to set mode: %s\n", strerror(-ret));
376 ret = FALSE;
377 } else {
378 ret = TRUE;
379
380 /* Force DPMS to On for all outputs, which the kernel will have done
381 * with the mode set. Also, restore the backlight level
382 */
383 for (i = 0; i < xf86_config->num_output; i++) {
384 xf86OutputPtr output = xf86_config->output[i];
385 struct intel_output *intel_output;
386
387 if (output->crtc != crtc)
388 continue;
389
390 intel_output = output->driver_private;
391 intel_output_dpms_backlight(output, intel_output->dpms_mode, DPMSModeOn);
392 intel_output->dpms_mode = DPMSModeOn;
393 }
394 }
395
396 if (scrn->pScreen)
397 xf86_reload_cursors(scrn->pScreen);
398
399 done:
400 free(output_ids);
401 return ret;
402 }
403
404 static Bool
intel_crtc_set_mode_major(xf86CrtcPtr crtc,DisplayModePtr mode,Rotation rotation,int x,int y)405 intel_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
406 Rotation rotation, int x, int y)
407 {
408 ScrnInfoPtr scrn = crtc->scrn;
409 intel_screen_private *intel = intel_get_screen_private(scrn);
410 struct intel_crtc *intel_crtc = crtc->driver_private;
411 struct intel_mode *intel_mode = intel_crtc->mode;
412 int saved_x, saved_y;
413 Rotation saved_rotation;
414 DisplayModeRec saved_mode;
415 int ret = TRUE;
416 unsigned int pitch = scrn->displayWidth * intel->cpp;
417
418 if (intel_mode->fb_id == 0) {
419 ret = drmModeAddFB(intel_mode->fd,
420 scrn->virtualX, scrn->virtualY,
421 scrn->depth, scrn->bitsPerPixel,
422 pitch, intel->front_buffer->handle,
423 &intel_mode->fb_id);
424 if (ret < 0) {
425 ErrorF("failed to add fb\n");
426 return FALSE;
427 }
428
429 drm_intel_bo_disable_reuse(intel->front_buffer);
430 }
431
432 saved_mode = crtc->mode;
433 saved_x = crtc->x;
434 saved_y = crtc->y;
435 saved_rotation = crtc->rotation;
436
437 crtc->mode = *mode;
438 crtc->x = x;
439 crtc->y = y;
440 crtc->rotation = rotation;
441
442 intel_flush(intel);
443
444 mode_to_kmode(crtc->scrn, &intel_crtc->kmode, mode);
445 ret = intel_crtc_apply(crtc);
446 if (!ret) {
447 crtc->x = saved_x;
448 crtc->y = saved_y;
449 crtc->rotation = saved_rotation;
450 crtc->mode = saved_mode;
451 }
452 return ret;
453 }
454
455 static void
intel_crtc_set_cursor_colors(xf86CrtcPtr crtc,int bg,int fg)456 intel_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
457 {
458
459 }
460
461 static void
intel_crtc_set_cursor_position(xf86CrtcPtr crtc,int x,int y)462 intel_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
463 {
464 struct intel_crtc *intel_crtc = crtc->driver_private;
465 struct intel_mode *mode = intel_crtc->mode;
466
467 drmModeMoveCursor(mode->fd, crtc_id(intel_crtc), x, y);
468 }
469
470 static int
__intel_crtc_load_cursor_argb(xf86CrtcPtr crtc,CARD32 * image)471 __intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
472 {
473 struct intel_crtc *intel_crtc = crtc->driver_private;
474 int ret;
475
476 ret = dri_bo_subdata(intel_crtc->cursor, 0, 64*64*4, image);
477 if (ret)
478 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
479 "failed to set cursor: %s\n", strerror(-ret));
480
481 return ret;
482 }
483
484 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2)
485 static Bool
intel_crtc_load_cursor_argb(xf86CrtcPtr crtc,CARD32 * image)486 intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
487 {
488 return __intel_crtc_load_cursor_argb(crtc, image) == 0;
489 }
490 #else
491 static void
intel_crtc_load_cursor_argb(xf86CrtcPtr crtc,CARD32 * image)492 intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
493 {
494 __intel_crtc_load_cursor_argb(crtc, image);
495 }
496 #endif
497
498 static void
intel_crtc_hide_cursor(xf86CrtcPtr crtc)499 intel_crtc_hide_cursor(xf86CrtcPtr crtc)
500 {
501 struct intel_crtc *intel_crtc = crtc->driver_private;
502 struct intel_mode *mode = intel_crtc->mode;
503
504 drmModeSetCursor(mode->fd, crtc_id(intel_crtc), 0, 64, 64);
505 }
506
507 static void
intel_crtc_show_cursor(xf86CrtcPtr crtc)508 intel_crtc_show_cursor(xf86CrtcPtr crtc)
509 {
510 struct intel_crtc *intel_crtc = crtc->driver_private;
511 struct intel_mode *mode = intel_crtc->mode;
512
513 drmModeSetCursor(mode->fd, crtc_id(intel_crtc),
514 intel_crtc->cursor->handle, 64, 64);
515 }
516
517 static void *
intel_crtc_shadow_allocate(xf86CrtcPtr crtc,int width,int height)518 intel_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
519 {
520 ScrnInfoPtr scrn = crtc->scrn;
521 struct intel_crtc *intel_crtc = crtc->driver_private;
522 struct intel_mode *mode = intel_crtc->mode;
523 int rotate_pitch;
524 uint32_t tiling;
525 int ret;
526
527 intel_crtc->rotate_bo = intel_allocate_framebuffer(scrn,
528 width, height,
529 mode->cpp,
530 &rotate_pitch,
531 &tiling);
532
533 if (!intel_crtc->rotate_bo) {
534 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
535 "Couldn't allocate shadow memory for rotated CRTC\n");
536 return NULL;
537 }
538
539 ret = drmModeAddFB(mode->fd, width, height, crtc->scrn->depth,
540 crtc->scrn->bitsPerPixel, rotate_pitch,
541 intel_crtc->rotate_bo->handle,
542 &intel_crtc->rotate_fb_id);
543 if (ret) {
544 ErrorF("failed to add rotate fb\n");
545 drm_intel_bo_unreference(intel_crtc->rotate_bo);
546 return NULL;
547 }
548
549 intel_crtc->rotate_pitch = rotate_pitch;
550 return intel_crtc->rotate_bo;
551 }
552
553 static PixmapPtr
intel_create_pixmap_header(ScreenPtr pScreen,int width,int height,int depth,int bitsPerPixel,int devKind,void * pPixData)554 intel_create_pixmap_header(ScreenPtr pScreen, int width, int height, int depth,
555 int bitsPerPixel, int devKind, void *pPixData)
556 {
557 PixmapPtr pixmap;
558
559 /* width and height of 0 means don't allocate any pixmap data */
560 pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
561
562 if (pixmap) {
563 if ((*pScreen->ModifyPixmapHeader) (pixmap, width, height, depth,
564 bitsPerPixel, devKind, pPixData))
565 {
566 return pixmap;
567 }
568 (*pScreen->DestroyPixmap) (pixmap);
569 }
570 return NullPixmap;
571 }
572
573 static PixmapPtr
intel_crtc_shadow_create(xf86CrtcPtr crtc,void * data,int width,int height)574 intel_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
575 {
576 ScrnInfoPtr scrn = crtc->scrn;
577 intel_screen_private *intel = intel_get_screen_private(scrn);
578 struct intel_crtc *intel_crtc = crtc->driver_private;
579 PixmapPtr rotate_pixmap;
580
581 if (!data) {
582 data = intel_crtc_shadow_allocate (crtc, width, height);
583 if (!data) {
584 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
585 "Couldn't allocate shadow pixmap for rotated CRTC\n");
586 return NULL;
587 }
588 }
589 if (intel_crtc->rotate_bo == NULL) {
590 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
591 "Couldn't allocate shadow pixmap for rotated CRTC\n");
592 return NULL;
593 }
594
595 rotate_pixmap = intel_create_pixmap_header(scrn->pScreen,
596 width, height,
597 scrn->depth,
598 scrn->bitsPerPixel,
599 intel_crtc->rotate_pitch,
600 NULL);
601
602 if (rotate_pixmap == NULL) {
603 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
604 "Couldn't allocate shadow pixmap for rotated CRTC\n");
605 return NULL;
606 }
607
608 intel_set_pixmap_bo(rotate_pixmap, intel_crtc->rotate_bo);
609
610 intel->shadow_present = TRUE;
611
612 return rotate_pixmap;
613 }
614
615 static void
intel_crtc_shadow_destroy(xf86CrtcPtr crtc,PixmapPtr rotate_pixmap,void * data)616 intel_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
617 {
618 ScrnInfoPtr scrn = crtc->scrn;
619 intel_screen_private *intel = intel_get_screen_private(scrn);
620 struct intel_crtc *intel_crtc = crtc->driver_private;
621 struct intel_mode *mode = intel_crtc->mode;
622
623 if (rotate_pixmap) {
624 intel_set_pixmap_bo(rotate_pixmap, NULL);
625 rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
626 }
627
628 if (data) {
629 /* Be sure to sync acceleration before the memory gets
630 * unbound. */
631 drmModeRmFB(mode->fd, intel_crtc->rotate_fb_id);
632 intel_crtc->rotate_fb_id = 0;
633
634 dri_bo_unreference(intel_crtc->rotate_bo);
635 intel_crtc->rotate_bo = NULL;
636 }
637
638 intel->shadow_present = FALSE;
639 }
640
641 static void
intel_crtc_gamma_set(xf86CrtcPtr crtc,CARD16 * red,CARD16 * green,CARD16 * blue,int size)642 intel_crtc_gamma_set(xf86CrtcPtr crtc,
643 CARD16 *red, CARD16 *green, CARD16 *blue, int size)
644 {
645 struct intel_crtc *intel_crtc = crtc->driver_private;
646 struct intel_mode *mode = intel_crtc->mode;
647
648 drmModeCrtcSetGamma(mode->fd, crtc_id(intel_crtc),
649 size, red, green, blue);
650 }
651
652 static void
intel_crtc_destroy(xf86CrtcPtr crtc)653 intel_crtc_destroy(xf86CrtcPtr crtc)
654 {
655 struct intel_crtc *intel_crtc = crtc->driver_private;
656
657 if (intel_crtc->cursor) {
658 drmModeSetCursor(intel_crtc->mode->fd, crtc_id(intel_crtc), 0, 64, 64);
659 drm_intel_bo_unreference(intel_crtc->cursor);
660 intel_crtc->cursor = NULL;
661 }
662
663 list_del(&intel_crtc->link);
664 free(intel_crtc);
665
666 crtc->driver_private = NULL;
667 }
668
669 #ifdef INTEL_PIXMAP_SHARING
670 static Bool
intel_set_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix)671 intel_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
672 {
673 struct intel_crtc *intel_crtc = crtc->driver_private;
674 ScrnInfoPtr scrn = crtc->scrn;
675 intel_screen_private *intel = intel_get_screen_private(scrn);
676 dri_bo *bo;
677
678 if (ppix == intel_crtc->scanout_pixmap)
679 return TRUE;
680
681 if (!ppix) {
682 intel_crtc->scanout_pixmap = NULL;
683 if (intel_crtc->scanout_fb_id) {
684 drmModeRmFB(intel->drmSubFD, intel_crtc->scanout_fb_id);
685 intel_crtc->scanout_fb_id = 0;
686 }
687 return TRUE;
688 }
689
690 bo = intel_get_pixmap_bo(ppix);
691 if (!bo)
692 return FALSE;
693
694 if (intel->front_buffer)
695 return FALSE;
696
697 drm_intel_bo_disable_reuse(bo);
698
699 intel_crtc->scanout_pixmap = ppix;
700 return drmModeAddFB(intel->drmSubFD, ppix->drawable.width,
701 ppix->drawable.height, ppix->drawable.depth,
702 ppix->drawable.bitsPerPixel, ppix->devKind,
703 bo->handle, &intel_crtc->scanout_fb_id) == 0;
704 }
705 #endif
706
707 static const xf86CrtcFuncsRec intel_crtc_funcs = {
708 .dpms = intel_crtc_dpms,
709 .set_mode_major = intel_crtc_set_mode_major,
710 .set_cursor_colors = intel_crtc_set_cursor_colors,
711 .set_cursor_position = intel_crtc_set_cursor_position,
712 .show_cursor = intel_crtc_show_cursor,
713 .hide_cursor = intel_crtc_hide_cursor,
714 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,3)
715 .load_cursor_argb_check = intel_crtc_load_cursor_argb,
716 #else
717 .load_cursor_argb = intel_crtc_load_cursor_argb,
718 #endif
719 .shadow_create = intel_crtc_shadow_create,
720 .shadow_allocate = intel_crtc_shadow_allocate,
721 .shadow_destroy = intel_crtc_shadow_destroy,
722 .gamma_set = intel_crtc_gamma_set,
723 .destroy = intel_crtc_destroy,
724 #ifdef INTEL_PIXMAP_SHARING
725 .set_scanout_pixmap = intel_set_scanout_pixmap,
726 #endif
727 };
728
729 static void
intel_crtc_init(ScrnInfoPtr scrn,struct intel_mode * mode,drmModeResPtr mode_res,int num)730 intel_crtc_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res, int num)
731 {
732 intel_screen_private *intel = intel_get_screen_private(scrn);
733 xf86CrtcPtr crtc;
734 struct intel_crtc *intel_crtc;
735
736 intel_crtc = calloc(sizeof(struct intel_crtc), 1);
737 if (intel_crtc == NULL)
738 return;
739
740 crtc = xf86CrtcCreate(scrn, &intel_crtc_funcs);
741 if (crtc == NULL) {
742 free(intel_crtc);
743 return;
744 }
745
746 intel_crtc->mode_crtc = drmModeGetCrtc(mode->fd,
747 mode_res->crtcs[num]);
748 if (intel_crtc->mode_crtc == NULL) {
749 free(intel_crtc);
750 return;
751 }
752
753 intel_crtc->mode = mode;
754 crtc->driver_private = intel_crtc;
755
756 intel_crtc->pipe = drm_intel_get_pipe_from_crtc_id(intel->bufmgr,
757 crtc_id(intel_crtc));
758
759 intel_crtc->cursor = drm_intel_bo_alloc(intel->bufmgr, "ARGB cursor",
760 4*64*64, 4096);
761
762 intel_crtc->crtc = crtc;
763 list_add(&intel_crtc->link, &mode->crtcs);
764 }
765
766 static Bool
is_panel(int type)767 is_panel(int type)
768 {
769 return (type == DRM_MODE_CONNECTOR_LVDS ||
770 type == DRM_MODE_CONNECTOR_eDP);
771 }
772
773 static xf86OutputStatus
intel_output_detect(xf86OutputPtr output)774 intel_output_detect(xf86OutputPtr output)
775 {
776 /* go to the hw and retrieve a new output struct */
777 struct intel_output *intel_output = output->driver_private;
778 struct intel_mode *mode = intel_output->mode;
779 xf86OutputStatus status;
780
781 drmModeFreeConnector(intel_output->mode_output);
782 intel_output->mode_output =
783 drmModeGetConnector(mode->fd, intel_output->output_id);
784 if (intel_output->mode_output == NULL) {
785 /* and hope we are safe everywhere else */
786 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
787 "drmModeGetConnector failed, reporting output disconnected\n");
788 return XF86OutputStatusDisconnected;
789 }
790
791 switch (intel_output->mode_output->connection) {
792 case DRM_MODE_CONNECTED:
793 status = XF86OutputStatusConnected;
794 break;
795 case DRM_MODE_DISCONNECTED:
796 status = XF86OutputStatusDisconnected;
797 break;
798 default:
799 case DRM_MODE_UNKNOWNCONNECTION:
800 status = XF86OutputStatusUnknown;
801 break;
802 }
803 return status;
804 }
805
806 static Bool
intel_output_mode_valid(xf86OutputPtr output,DisplayModePtr pModes)807 intel_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
808 {
809 struct intel_output *intel_output = output->driver_private;
810
811 /*
812 * If the connector type is a panel, we will use the panel limit to
813 * verfiy whether the mode is valid.
814 */
815 if (intel_output->has_panel_limits) {
816 if (pModes->HDisplay > intel_output->panel_hdisplay ||
817 pModes->VDisplay > intel_output->panel_vdisplay)
818 return MODE_PANEL;
819 }
820
821 return MODE_OK;
822 }
823
824 static void
intel_output_attach_edid(xf86OutputPtr output)825 intel_output_attach_edid(xf86OutputPtr output)
826 {
827 struct intel_output *intel_output = output->driver_private;
828 drmModeConnectorPtr koutput = intel_output->mode_output;
829 struct intel_mode *mode = intel_output->mode;
830 xf86MonPtr mon = NULL;
831 int i;
832
833 if (!koutput) {
834 xf86OutputSetEDID(output, mon);
835 return;
836 }
837
838 /* look for an EDID property */
839 for (i = 0; i < koutput->count_props; i++) {
840 drmModePropertyPtr props;
841
842 props = drmModeGetProperty(mode->fd, koutput->props[i]);
843 if (!props)
844 continue;
845
846 if (!(props->flags & DRM_MODE_PROP_BLOB)) {
847 drmModeFreeProperty(props);
848 continue;
849 }
850
851 if (!strcmp(props->name, "EDID")) {
852 drmModeFreePropertyBlob(intel_output->edid_blob);
853 intel_output->edid_blob =
854 drmModeGetPropertyBlob(mode->fd,
855 koutput->prop_values[i]);
856 }
857 drmModeFreeProperty(props);
858 }
859
860 if (intel_output->edid_blob) {
861 mon = xf86InterpretEDID(output->scrn->scrnIndex,
862 intel_output->edid_blob->data);
863
864 if (mon && intel_output->edid_blob->length > 128)
865 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
866 }
867
868 xf86OutputSetEDID(output, mon);
869 }
870
871 static void
intel_output_attach_tile(xf86OutputPtr output)872 intel_output_attach_tile(xf86OutputPtr output)
873 {
874 #if XF86_OUTPUT_VERSION >= 3
875 struct intel_output *intel_output = output->driver_private;
876 drmModeConnectorPtr koutput = intel_output->mode_output;
877 struct intel_mode *mode = intel_output->mode;
878 drmModePropertyBlobPtr blob = NULL;
879 struct xf86CrtcTileInfo tile_info, *set = NULL;
880 int i;
881
882 for (i = 0; koutput && i < koutput->count_props; i++) {
883 drmModePropertyPtr props;
884
885 props = drmModeGetProperty(mode->fd, koutput->props[i]);
886 if (!props)
887 continue;
888
889 if (!(props->flags & DRM_MODE_PROP_BLOB)) {
890 drmModeFreeProperty(props);
891 continue;
892 }
893
894 if (!strcmp(props->name, "TILE")) {
895 blob = drmModeGetPropertyBlob(mode->fd,
896 koutput->prop_values[i]);
897 }
898 drmModeFreeProperty(props);
899 }
900
901 if (blob) {
902 if (xf86OutputParseKMSTile(blob->data,
903 blob->length,
904 &tile_info))
905 set = &tile_info;
906 drmModeFreePropertyBlob(blob);
907 }
908
909 xf86OutputSetTile(output, set);
910 #endif
911 }
912
913 static DisplayModePtr
intel_output_panel_edid(xf86OutputPtr output,DisplayModePtr modes)914 intel_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
915 {
916 xf86MonPtr mon = output->MonInfo;
917
918 if (!mon || !GTF_SUPPORTED(mon->features.msc)) {
919 DisplayModePtr i, m, p = NULL;
920 int max_x = 0, max_y = 0;
921 float max_vrefresh = 0.0;
922
923 for (m = modes; m; m = m->next) {
924 if (m->type & M_T_PREFERRED)
925 p = m;
926 max_x = max(max_x, m->HDisplay);
927 max_y = max(max_y, m->VDisplay);
928 max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
929 }
930
931 max_vrefresh = max(max_vrefresh, 60.0);
932 max_vrefresh *= (1 + SYNC_TOLERANCE);
933
934 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0)
935 m = xf86GetDefaultModes();
936 #else
937 m = xf86GetDefaultModes(0,0);
938 #endif
939
940 xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
941
942 for (i = m; i; i = i->next) {
943 if (xf86ModeVRefresh(i) > max_vrefresh)
944 i->status = MODE_VSYNC;
945 if (p && i->HDisplay >= p->HDisplay &&
946 i->VDisplay >= p->VDisplay &&
947 xf86ModeVRefresh(i) >= xf86ModeVRefresh(p))
948 i->status = MODE_VSYNC;
949 }
950
951 xf86PruneInvalidModes(output->scrn, &m, FALSE);
952
953 modes = xf86ModesAdd(modes, m);
954 }
955
956 return modes;
957 }
958
959 static DisplayModePtr
intel_output_get_modes(xf86OutputPtr output)960 intel_output_get_modes(xf86OutputPtr output)
961 {
962 struct intel_output *intel_output = output->driver_private;
963 drmModeConnectorPtr koutput = intel_output->mode_output;
964 DisplayModePtr Modes = NULL;
965 int i;
966
967 intel_output_attach_edid(output);
968 intel_output_attach_tile(output);
969
970 if (!koutput)
971 return Modes;
972
973 /* modes should already be available */
974 for (i = 0; i < koutput->count_modes; i++) {
975 DisplayModePtr Mode;
976
977 Mode = calloc(1, sizeof(DisplayModeRec));
978 if (Mode) {
979 mode_from_kmode(output->scrn, &koutput->modes[i], Mode);
980 Modes = xf86ModesAdd(Modes, Mode);
981 }
982 }
983
984 /*
985 * If the connector type is a panel, we will traverse the kernel mode to
986 * get the panel limit. And then add all the standard modes to fake
987 * the fullscreen experience.
988 * If it is incorrect, please fix me.
989 */
990 intel_output->has_panel_limits = FALSE;
991 if (is_panel(koutput->connector_type)) {
992 for (i = 0; i < koutput->count_modes; i++) {
993 drmModeModeInfo *mode_ptr;
994
995 mode_ptr = &koutput->modes[i];
996 if (mode_ptr->hdisplay > intel_output->panel_hdisplay)
997 intel_output->panel_hdisplay = mode_ptr->hdisplay;
998 if (mode_ptr->vdisplay > intel_output->panel_vdisplay)
999 intel_output->panel_vdisplay = mode_ptr->vdisplay;
1000 }
1001
1002 intel_output->has_panel_limits =
1003 intel_output->panel_hdisplay &&
1004 intel_output->panel_vdisplay;
1005
1006 Modes = intel_output_panel_edid(output, Modes);
1007 }
1008
1009 return Modes;
1010 }
1011
1012 static void
intel_output_destroy(xf86OutputPtr output)1013 intel_output_destroy(xf86OutputPtr output)
1014 {
1015 struct intel_output *intel_output = output->driver_private;
1016 int i;
1017
1018 drmModeFreePropertyBlob(intel_output->edid_blob);
1019
1020 for (i = 0; i < intel_output->num_props; i++) {
1021 drmModeFreeProperty(intel_output->props[i].mode_prop);
1022 free(intel_output->props[i].atoms);
1023 }
1024 free(intel_output->props);
1025 for (i = 0; i < intel_output->mode_output->count_encoders; i++) {
1026 drmModeFreeEncoder(intel_output->mode_encoders[i]);
1027 }
1028 free(intel_output->mode_encoders);
1029 drmModeFreeConnector(intel_output->mode_output);
1030 intel_output->mode_output = NULL;
1031
1032 list_del(&intel_output->link);
1033 backlight_close(&intel_output->backlight);
1034 free(intel_output);
1035
1036 output->driver_private = NULL;
1037 }
1038
1039 static void
intel_output_dpms_backlight(xf86OutputPtr output,int oldmode,int mode)1040 intel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode)
1041 {
1042 struct intel_output *intel_output = output->driver_private;
1043
1044 if (!intel_output->backlight.iface)
1045 return;
1046
1047 if (mode == DPMSModeOn) {
1048 /* If we're going from off->on we may need to turn on the backlight. */
1049 if (oldmode != DPMSModeOn)
1050 intel_output_backlight_set(output,
1051 intel_output->backlight_active_level);
1052 } else {
1053 /* Only save the current backlight value if we're going from on to off. */
1054 if (oldmode == DPMSModeOn)
1055 intel_output->backlight_active_level = intel_output_backlight_get(output);
1056 intel_output_backlight_set(output, 0);
1057 }
1058 }
1059
1060 static void
intel_output_dpms(xf86OutputPtr output,int dpms)1061 intel_output_dpms(xf86OutputPtr output, int dpms)
1062 {
1063 struct intel_output *intel_output = output->driver_private;
1064 drmModeConnectorPtr koutput = intel_output->mode_output;
1065 struct intel_mode *mode = intel_output->mode;
1066 int i;
1067
1068 if (!koutput)
1069 return;
1070
1071 for (i = 0; i < koutput->count_props; i++) {
1072 drmModePropertyPtr props;
1073
1074 props = drmModeGetProperty(mode->fd, koutput->props[i]);
1075 if (!props)
1076 continue;
1077
1078 if (!strcmp(props->name, "DPMS")) {
1079 /* Make sure to reverse the order between on and off. */
1080 if (dpms != DPMSModeOn)
1081 intel_output_dpms_backlight(output,
1082 intel_output->dpms_mode,
1083 dpms);
1084
1085 drmModeConnectorSetProperty(mode->fd,
1086 intel_output->output_id,
1087 props->prop_id,
1088 dpms);
1089
1090 if (dpms == DPMSModeOn)
1091 intel_output_dpms_backlight(output,
1092 intel_output->dpms_mode,
1093 dpms);
1094 intel_output->dpms_mode = dpms;
1095 drmModeFreeProperty(props);
1096 return;
1097 }
1098
1099 drmModeFreeProperty(props);
1100 }
1101 }
1102
1103 int
intel_output_dpms_status(xf86OutputPtr output)1104 intel_output_dpms_status(xf86OutputPtr output)
1105 {
1106 struct intel_output *intel_output = output->driver_private;
1107 return intel_output->dpms_mode;
1108 }
1109
1110 static Bool
intel_property_ignore(drmModePropertyPtr prop)1111 intel_property_ignore(drmModePropertyPtr prop)
1112 {
1113 if (!prop)
1114 return TRUE;
1115
1116 /* ignore blob prop */
1117 if (prop->flags & DRM_MODE_PROP_BLOB)
1118 return TRUE;
1119
1120 /* ignore standard property */
1121 if (!strcmp(prop->name, "EDID") ||
1122 !strcmp(prop->name, "DPMS"))
1123 return TRUE;
1124
1125 return FALSE;
1126 }
1127
1128 static void
intel_output_create_ranged_atom(xf86OutputPtr output,Atom * atom,const char * name,INT32 min,INT32 max,uint64_t value,Bool immutable)1129 intel_output_create_ranged_atom(xf86OutputPtr output, Atom *atom,
1130 const char *name, INT32 min, INT32 max,
1131 uint64_t value, Bool immutable)
1132 {
1133 int err;
1134 INT32 atom_range[2];
1135
1136 atom_range[0] = min;
1137 atom_range[1] = max;
1138
1139 *atom = MakeAtom(name, strlen(name), TRUE);
1140
1141 err = RRConfigureOutputProperty(output->randr_output, *atom, FALSE,
1142 TRUE, immutable, 2, atom_range);
1143 if (err != 0)
1144 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1145 "RRConfigureOutputProperty error, %d\n", err);
1146
1147 err = RRChangeOutputProperty(output->randr_output, *atom, XA_INTEGER,
1148 32, PropModeReplace, 1, &value, FALSE,
1149 FALSE);
1150 if (err != 0)
1151 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1152 "RRChangeOutputProperty error, %d\n", err);
1153 }
1154
1155 #define BACKLIGHT_NAME "Backlight"
1156 #define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT"
1157 static Atom backlight_atom, backlight_deprecated_atom;
1158
1159 static void
intel_output_create_resources(xf86OutputPtr output)1160 intel_output_create_resources(xf86OutputPtr output)
1161 {
1162 struct intel_output *intel_output = output->driver_private;
1163 drmModeConnectorPtr mode_output = intel_output->mode_output;
1164 struct intel_mode *mode = intel_output->mode;
1165 int i, j, err;
1166
1167 intel_output->props = calloc(mode_output->count_props,
1168 sizeof(struct intel_property));
1169 if (!intel_output->props)
1170 return;
1171
1172 intel_output->num_props = 0;
1173 for (i = j = 0; i < mode_output->count_props; i++) {
1174 drmModePropertyPtr drmmode_prop;
1175
1176 drmmode_prop = drmModeGetProperty(mode->fd,
1177 mode_output->props[i]);
1178 if (intel_property_ignore(drmmode_prop)) {
1179 drmModeFreeProperty(drmmode_prop);
1180 continue;
1181 }
1182
1183 intel_output->props[j].mode_prop = drmmode_prop;
1184 intel_output->props[j].value = mode_output->prop_values[i];
1185 j++;
1186 }
1187 intel_output->num_props = j;
1188
1189 for (i = 0; i < intel_output->num_props; i++) {
1190 struct intel_property *p = &intel_output->props[i];
1191 drmModePropertyPtr drmmode_prop = p->mode_prop;
1192
1193 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1194 p->num_atoms = 1;
1195 p->atoms = calloc(p->num_atoms, sizeof(Atom));
1196 if (!p->atoms)
1197 continue;
1198
1199 intel_output_create_ranged_atom(output, &p->atoms[0],
1200 drmmode_prop->name,
1201 drmmode_prop->values[0],
1202 drmmode_prop->values[1],
1203 p->value,
1204 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE);
1205
1206 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1207 p->num_atoms = drmmode_prop->count_enums + 1;
1208 p->atoms = calloc(p->num_atoms, sizeof(Atom));
1209 if (!p->atoms)
1210 continue;
1211
1212 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1213 for (j = 1; j <= drmmode_prop->count_enums; j++) {
1214 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
1215 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
1216 }
1217
1218 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1219 FALSE, FALSE,
1220 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1221 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
1222 if (err != 0) {
1223 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1224 "RRConfigureOutputProperty error, %d\n", err);
1225 }
1226
1227 for (j = 0; j < drmmode_prop->count_enums; j++)
1228 if (drmmode_prop->enums[j].value == p->value)
1229 break;
1230 /* there's always a matching value */
1231 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1232 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE);
1233 if (err != 0) {
1234 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1235 "RRChangeOutputProperty error, %d\n", err);
1236 }
1237 }
1238 }
1239
1240 if (intel_output->backlight.iface) {
1241 /* Set up the backlight property, which takes effect
1242 * immediately and accepts values only within the
1243 * backlight_range.
1244 */
1245 intel_output_create_ranged_atom(output, &backlight_atom,
1246 BACKLIGHT_NAME, 0,
1247 intel_output->backlight.max,
1248 intel_output->backlight_active_level,
1249 FALSE);
1250 intel_output_create_ranged_atom(output,
1251 &backlight_deprecated_atom,
1252 BACKLIGHT_DEPRECATED_NAME, 0,
1253 intel_output->backlight.max,
1254 intel_output->backlight_active_level,
1255 FALSE);
1256 }
1257 }
1258
1259 static Bool
intel_output_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)1260 intel_output_set_property(xf86OutputPtr output, Atom property,
1261 RRPropertyValuePtr value)
1262 {
1263 struct intel_output *intel_output = output->driver_private;
1264 struct intel_mode *mode = intel_output->mode;
1265 int i;
1266
1267 if (property == backlight_atom || property == backlight_deprecated_atom) {
1268 INT32 val;
1269
1270 if (value->type != XA_INTEGER || value->format != 32 ||
1271 value->size != 1)
1272 {
1273 return FALSE;
1274 }
1275
1276 val = *(INT32 *)value->data;
1277 if (val < 0 || val > intel_output->backlight.max)
1278 return FALSE;
1279
1280 if (intel_output->dpms_mode == DPMSModeOn)
1281 intel_output_backlight_set(output, val);
1282 intel_output->backlight_active_level = val;
1283 return TRUE;
1284 }
1285
1286 for (i = 0; i < intel_output->num_props; i++) {
1287 struct intel_property *p = &intel_output->props[i];
1288
1289 if (p->atoms[0] != property)
1290 continue;
1291
1292 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1293 uint32_t val;
1294
1295 if (value->type != XA_INTEGER || value->format != 32 ||
1296 value->size != 1)
1297 return FALSE;
1298 val = *(uint32_t *)value->data;
1299
1300 drmModeConnectorSetProperty(mode->fd, intel_output->output_id,
1301 p->mode_prop->prop_id, (uint64_t)val);
1302 return TRUE;
1303 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1304 Atom atom;
1305 const char *name;
1306 int j;
1307
1308 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
1309 return FALSE;
1310 memcpy(&atom, value->data, 4);
1311 name = NameForAtom(atom);
1312 if (name == NULL)
1313 return FALSE;
1314
1315 /* search for matching name string, then set its value down */
1316 for (j = 0; j < p->mode_prop->count_enums; j++) {
1317 if (!strcmp(p->mode_prop->enums[j].name, name)) {
1318 drmModeConnectorSetProperty(mode->fd, intel_output->output_id,
1319 p->mode_prop->prop_id, p->mode_prop->enums[j].value);
1320 return TRUE;
1321 }
1322 }
1323 return FALSE;
1324 }
1325 }
1326
1327 /* We didn't recognise this property, just report success in order
1328 * to allow the set to continue, otherwise we break setting of
1329 * common properties like EDID.
1330 */
1331 return TRUE;
1332 }
1333
1334 static Bool
intel_output_get_property(xf86OutputPtr output,Atom property)1335 intel_output_get_property(xf86OutputPtr output, Atom property)
1336 {
1337 struct intel_output *intel_output = output->driver_private;
1338 int err;
1339
1340 if (property == backlight_atom || property == backlight_deprecated_atom) {
1341 INT32 val;
1342
1343 if (!intel_output->backlight.iface)
1344 return FALSE;
1345
1346 if (intel_output->dpms_mode == DPMSModeOn) {
1347 val = intel_output_backlight_get(output);
1348 if (val < 0)
1349 return FALSE;
1350 } else {
1351 val = intel_output->backlight_active_level;
1352 }
1353
1354 err = RRChangeOutputProperty(output->randr_output, property,
1355 XA_INTEGER, 32, PropModeReplace, 1, &val,
1356 FALSE, FALSE);
1357 if (err != 0) {
1358 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1359 "RRChangeOutputProperty error, %d\n", err);
1360 return FALSE;
1361 }
1362
1363 return TRUE;
1364 }
1365
1366 return FALSE;
1367 }
1368
1369 static const xf86OutputFuncsRec intel_output_funcs = {
1370 .create_resources = intel_output_create_resources,
1371 #ifdef RANDR_12_INTERFACE
1372 .set_property = intel_output_set_property,
1373 .get_property = intel_output_get_property,
1374 #endif
1375 .dpms = intel_output_dpms,
1376 #if 0
1377
1378 .save = drmmode_crt_save,
1379 .restore = drmmode_crt_restore,
1380 .mode_fixup = drmmode_crt_mode_fixup,
1381 .prepare = intel_output_prepare,
1382 .mode_set = drmmode_crt_mode_set,
1383 .commit = intel_output_commit,
1384 #endif
1385 .detect = intel_output_detect,
1386 .mode_valid = intel_output_mode_valid,
1387
1388 .get_modes = intel_output_get_modes,
1389 .destroy = intel_output_destroy
1390 };
1391
1392 static const int subpixel_conv_table[7] = {
1393 0,
1394 SubPixelUnknown,
1395 SubPixelHorizontalRGB,
1396 SubPixelHorizontalBGR,
1397 SubPixelVerticalRGB,
1398 SubPixelVerticalBGR,
1399 SubPixelNone
1400 };
1401
1402 static const char *output_names[] = {
1403 "None",
1404 "VGA",
1405 "DVI",
1406 "DVI",
1407 "DVI",
1408 "Composite",
1409 "TV",
1410 "LVDS",
1411 "CTV",
1412 "DIN",
1413 "DP",
1414 "HDMI",
1415 "HDMI",
1416 "TV",
1417 "eDP",
1418 };
1419
find_output(ScrnInfoPtr pScrn,int id)1420 static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
1421 {
1422 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1423 int i;
1424 for (i = 0; i < xf86_config->num_output; i++) {
1425 xf86OutputPtr output = xf86_config->output[i];
1426 struct intel_output *intel_output;
1427
1428 intel_output = output->driver_private;
1429 if (intel_output->output_id == id)
1430 return output;
1431 }
1432 return NULL;
1433 }
1434
parse_path_blob(drmModePropertyBlobPtr path_blob,int * conn_base_id,char ** path)1435 static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
1436 {
1437 char *conn;
1438 char conn_id[5];
1439 int id, len;
1440 char *blob_data;
1441
1442 if (!path_blob)
1443 return -1;
1444
1445 blob_data = path_blob->data;
1446 /* we only handle MST paths for now */
1447 if (strncmp(blob_data, "mst:", 4))
1448 return -1;
1449
1450 conn = strchr(blob_data + 4, '-');
1451 if (!conn)
1452 return -1;
1453 len = conn - (blob_data + 4);
1454 if (len + 1 > 5)
1455 return -1;
1456 memcpy(conn_id, blob_data + 4, len);
1457 conn_id[len] = '\0';
1458 id = strtoul(conn_id, NULL, 10);
1459
1460 *conn_base_id = id;
1461
1462 *path = conn + 1;
1463 return 0;
1464 }
1465
1466 static void
drmmode_create_name(ScrnInfoPtr pScrn,drmModeConnectorPtr koutput,char * name,drmModePropertyBlobPtr path_blob)1467 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
1468 drmModePropertyBlobPtr path_blob)
1469 {
1470 xf86OutputPtr output;
1471 int conn_id;
1472 char *extra_path;
1473
1474 output = NULL;
1475 if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
1476 output = find_output(pScrn, conn_id);
1477 if (output) {
1478 snprintf(name, 32, "%s-%s", output->name, extra_path);
1479 } else {
1480 const char *output_name;
1481
1482 if (koutput->connector_type < ARRAY_SIZE(output_names))
1483 output_name = output_names[koutput->connector_type];
1484 else
1485 output_name = "UNKNOWN";
1486
1487 snprintf(name, 32, "%s-%d",
1488 output_name, koutput->connector_type_id);
1489 }
1490 }
1491
1492 static void
intel_output_init(ScrnInfoPtr scrn,struct intel_mode * mode,drmModeResPtr mode_res,int num,int dynamic)1493 intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res, int num, int dynamic)
1494 {
1495 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1496 xf86OutputPtr output;
1497 drmModeConnectorPtr koutput;
1498 drmModeEncoderPtr *kencoders = NULL;
1499 struct intel_output *intel_output;
1500 char name[32];
1501 drmModePropertyPtr props;
1502 drmModePropertyBlobPtr path_blob = NULL;
1503 int i;
1504
1505 koutput = drmModeGetConnector(mode->fd,
1506 mode_res->connectors[num]);
1507 if (!koutput)
1508 return;
1509 for (i = 0; i < koutput->count_props; i++) {
1510 props = drmModeGetProperty(mode->fd, koutput->props[i]);
1511 if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
1512 if (!strcmp(props->name, "PATH")) {
1513 path_blob = drmModeGetPropertyBlob(mode->fd, koutput->prop_values[i]);
1514
1515 drmModeFreeProperty(props);
1516 break;
1517 }
1518 drmModeFreeProperty(props);
1519 }
1520 }
1521
1522 drmmode_create_name(scrn, koutput, name, path_blob);
1523 if (path_blob)
1524 drmModeFreePropertyBlob(path_blob);
1525
1526 if (path_blob && dynamic) {
1527 /* See if we have an output with this name already
1528 * and hook stuff up.
1529 */
1530 for (i = 0; i < xf86_config->num_output; i++) {
1531 output = xf86_config->output[i];
1532
1533 if (strncmp(output->name, name, 32))
1534 continue;
1535
1536 intel_output = output->driver_private;
1537 intel_output->output_id = mode_res->connectors[num];
1538 intel_output->mode_output = koutput;
1539 RROutputChanged(output->randr_output, TRUE);
1540 return;
1541 }
1542 }
1543 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
1544 if (!kencoders) {
1545 goto out_free_encoders;
1546 }
1547
1548 for (i = 0; i < koutput->count_encoders; i++) {
1549 kencoders[i] = drmModeGetEncoder(mode->fd, koutput->encoders[i]);
1550 if (!kencoders[i])
1551 goto out_free_encoders;
1552 }
1553
1554 output = xf86OutputCreate (scrn, &intel_output_funcs, name);
1555 if (!output) {
1556 goto out_free_encoders;
1557 }
1558
1559 intel_output = calloc(sizeof(struct intel_output), 1);
1560 if (!intel_output) {
1561 xf86OutputDestroy(output);
1562 goto out_free_encoders;
1563 }
1564
1565 intel_output->output_id = mode_res->connectors[num];
1566 intel_output->mode_output = koutput;
1567 intel_output->mode_encoders = kencoders;
1568 intel_output->mode = mode;
1569
1570 output->mm_width = koutput->mmWidth;
1571 output->mm_height = koutput->mmHeight;
1572
1573 output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1574 output->driver_private = intel_output;
1575
1576 if (is_panel(koutput->connector_type))
1577 intel_output_backlight_init(output);
1578
1579 output->possible_crtcs = 0x7f;
1580 for (i = 0; i < koutput->count_encoders; i++) {
1581 output->possible_crtcs &= kencoders[i]->possible_crtcs;
1582 }
1583 output->interlaceAllowed = TRUE;
1584
1585 intel_output->output = output;
1586
1587 if (dynamic) {
1588 output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), output->name, strlen(output->name), output);
1589 intel_output_create_resources(output);
1590 }
1591
1592 list_add(&intel_output->link, &mode->outputs);
1593 return;
1594
1595 out_free_encoders:
1596 if (kencoders) {
1597 for (i = 0; i < koutput->count_encoders; i++)
1598 drmModeFreeEncoder(kencoders[i]);
1599 free(kencoders);
1600 }
1601 drmModeFreeConnector(koutput);
1602 }
1603
1604 static Bool
intel_xf86crtc_resize(ScrnInfoPtr scrn,int width,int height)1605 intel_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
1606 {
1607 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1608 struct intel_crtc *intel_crtc = xf86_config->crtc[0]->driver_private;
1609 struct intel_mode *mode = intel_crtc->mode;
1610 intel_screen_private *intel = intel_get_screen_private(scrn);
1611 drm_intel_bo *old_front = NULL;
1612 Bool ret;
1613 uint32_t old_fb_id;
1614 int i, old_width, old_height, old_pitch;
1615 int pitch;
1616 uint32_t tiling;
1617
1618 if (scrn->virtualX == width && scrn->virtualY == height)
1619 return TRUE;
1620
1621 intel_flush(intel);
1622
1623 old_width = scrn->virtualX;
1624 old_height = scrn->virtualY;
1625 old_pitch = scrn->displayWidth;
1626 old_fb_id = mode->fb_id;
1627 old_front = intel->front_buffer;
1628
1629 if (intel->back_buffer) {
1630 drm_intel_bo_unreference(intel->back_buffer);
1631 intel->back_buffer = NULL;
1632 }
1633
1634 intel->front_buffer = intel_allocate_framebuffer(scrn,
1635 width, height,
1636 intel->cpp,
1637 &pitch, &tiling);
1638 if (!intel->front_buffer)
1639 goto fail;
1640
1641 ret = drmModeAddFB(mode->fd, width, height, scrn->depth,
1642 scrn->bitsPerPixel, pitch,
1643 intel->front_buffer->handle,
1644 &mode->fb_id);
1645 if (ret)
1646 goto fail;
1647
1648 intel->front_pitch = pitch;
1649 intel->front_tiling = tiling;
1650
1651 scrn->virtualX = width;
1652 scrn->virtualY = height;
1653
1654 if (!intel_uxa_create_screen_resources(scrn->pScreen))
1655 goto fail;
1656
1657 for (i = 0; i < xf86_config->num_crtc; i++) {
1658 xf86CrtcPtr crtc = xf86_config->crtc[i];
1659
1660 if (!crtc->enabled)
1661 continue;
1662
1663 if (!intel_crtc_apply(crtc))
1664 goto fail;
1665 }
1666
1667 if (old_fb_id)
1668 drmModeRmFB(mode->fd, old_fb_id);
1669 if (old_front)
1670 drm_intel_bo_unreference(old_front);
1671
1672 return TRUE;
1673
1674 fail:
1675 if (intel->front_buffer)
1676 drm_intel_bo_unreference(intel->front_buffer);
1677 intel->front_buffer = old_front;
1678 scrn->virtualX = old_width;
1679 scrn->virtualY = old_height;
1680 scrn->displayWidth = old_pitch;
1681 if (old_fb_id != mode->fb_id)
1682 drmModeRmFB(mode->fd, mode->fb_id);
1683 mode->fb_id = old_fb_id;
1684
1685 return FALSE;
1686 }
1687
1688 static void
1689 intel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
1690 uint64_t frame, uint64_t usec, void *data);
1691
1692 static void
1693 intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data);
1694
1695 static void
1696 intel_pageflip_complete(struct intel_mode *mode);
1697
1698 Bool
intel_do_pageflip(intel_screen_private * intel,dri_bo * new_front,int ref_crtc_hw_id,Bool async,void * pageflip_data,intel_pageflip_handler_proc pageflip_handler,intel_pageflip_abort_proc pageflip_abort)1699 intel_do_pageflip(intel_screen_private *intel,
1700 dri_bo *new_front,
1701 int ref_crtc_hw_id,
1702 Bool async,
1703 void *pageflip_data,
1704 intel_pageflip_handler_proc pageflip_handler,
1705 intel_pageflip_abort_proc pageflip_abort)
1706 {
1707 ScrnInfoPtr scrn = intel->scrn;
1708 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1709 struct intel_crtc *crtc = config->crtc[0]->driver_private;
1710 struct intel_mode *mode = crtc->mode;
1711 unsigned int pitch = scrn->displayWidth * intel->cpp;
1712 struct intel_pageflip *flip;
1713 uint32_t new_fb_id;
1714 uint32_t flags;
1715 uint32_t seq;
1716 int err = 0;
1717 int i;
1718
1719 /*
1720 * We only have a single length queue in the kernel, so any
1721 * attempts to schedule a second flip before processing the first
1722 * is a bug. Punt it back to the caller.
1723 */
1724 if (mode->flip_count)
1725 return FALSE;
1726
1727 /*
1728 * Create a new handle for the back buffer
1729 */
1730 if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
1731 scrn->depth, scrn->bitsPerPixel, pitch,
1732 new_front->handle, &new_fb_id)) {
1733 err = errno;
1734 goto error_out;
1735 }
1736
1737 drm_intel_bo_disable_reuse(new_front);
1738 intel_flush(intel);
1739
1740 /*
1741 * Queue flips on all enabled CRTCs
1742 * Note that if/when we get per-CRTC buffers, we'll have to update this.
1743 * Right now it assumes a single shared fb across all CRTCs, with the
1744 * kernel fixing up the offset of each CRTC as necessary.
1745 *
1746 * Also, flips queued on disabled or incorrectly configured displays
1747 * may never complete; this is a configuration error.
1748 */
1749 mode->fe_msc = 0;
1750 mode->fe_usec = 0;
1751 memset(&mode->pageflip, 0, sizeof(mode->pageflip));
1752
1753 flags = DRM_MODE_PAGE_FLIP_EVENT;
1754 if (async)
1755 flags |= DRM_MODE_PAGE_FLIP_ASYNC;
1756 for (i = 0; i < config->num_crtc; i++) {
1757 if (!intel_crtc_on(config->crtc[i]))
1758 continue;
1759
1760 crtc = config->crtc[i]->driver_private;
1761
1762 flip = calloc(1, sizeof(struct intel_pageflip));
1763 if (flip == NULL) {
1764 err = errno;
1765 goto error_undo;
1766 }
1767
1768 /* Only the reference crtc will finally deliver its page flip
1769 * completion event. All other crtc's events will be discarded.
1770 */
1771 flip->dispatch_me = (intel_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id);
1772 flip->mode = mode;
1773
1774 seq = intel_drm_queue_alloc(scrn, config->crtc[i], flip, intel_pageflip_handler, intel_pageflip_abort);
1775 if (!seq) {
1776 err = errno;
1777 free(flip);
1778 goto error_undo;
1779 }
1780
1781 mode->flip_count++;
1782
1783 if (drmModePageFlip(mode->fd,
1784 crtc_id(crtc),
1785 new_fb_id,
1786 flags, (void *)(uintptr_t)seq)) {
1787 err = errno;
1788 intel_drm_abort_seq(scrn, seq);
1789 goto error_undo;
1790 }
1791 }
1792
1793 mode->old_fb_id = mode->fb_id;
1794 mode->fb_id = new_fb_id;
1795
1796 mode->pageflip.data = pageflip_data;
1797 mode->pageflip.handler = pageflip_handler;
1798 mode->pageflip.abort = pageflip_abort;
1799
1800 if (!mode->flip_count)
1801 intel_pageflip_complete(mode);
1802
1803 return TRUE;
1804
1805 error_undo:
1806 drmModeRmFB(mode->fd, new_fb_id);
1807 for (i = 0; i < config->num_crtc; i++) {
1808 if (config->crtc[i]->enabled)
1809 intel_crtc_apply(config->crtc[i]);
1810 }
1811
1812 error_out:
1813 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
1814 strerror(err));
1815
1816 mode->flip_count = 0;
1817 return FALSE;
1818 }
1819
1820 static const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = {
1821 .resize = intel_xf86crtc_resize,
1822 };
1823
1824 /*
1825 * Enqueue a potential drm response; when the associated response
1826 * appears, we've got data to pass to the handler from here
1827 */
1828 uint32_t
intel_drm_queue_alloc(ScrnInfoPtr scrn,xf86CrtcPtr crtc,void * data,intel_drm_handler_proc handler,intel_drm_abort_proc abort)1829 intel_drm_queue_alloc(ScrnInfoPtr scrn,
1830 xf86CrtcPtr crtc,
1831 void *data,
1832 intel_drm_handler_proc handler,
1833 intel_drm_abort_proc abort)
1834 {
1835 struct intel_drm_queue *q;
1836
1837 q = calloc(1, sizeof(struct intel_drm_queue));
1838 if (!q)
1839 return 0;
1840
1841 if (!intel_drm_seq)
1842 ++intel_drm_seq;
1843 q->seq = intel_drm_seq++;
1844 q->scrn = scrn;
1845 q->crtc = crtc;
1846 q->data = data;
1847 q->handler = handler;
1848 q->abort = abort;
1849
1850 list_add(&q->list, &intel_drm_queue);
1851
1852 return q->seq;
1853 }
1854
1855 /*
1856 * Abort one queued DRM entry, removing it
1857 * from the list, calling the abort function and
1858 * freeing the memory
1859 */
1860 static void
intel_drm_abort_one(struct intel_drm_queue * q)1861 intel_drm_abort_one(struct intel_drm_queue *q)
1862 {
1863 list_del(&q->list);
1864 q->abort(q->scrn, q->crtc, q->data);
1865 free(q);
1866 }
1867
1868 /*
1869 * Externally usable abort function that uses a callback to match a single queued
1870 * entry to abort
1871 */
1872 void
intel_drm_abort(ScrnInfoPtr scrn,Bool (* match)(void * data,void * match_data),void * match_data)1873 intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data)
1874 {
1875 struct intel_drm_queue *q;
1876
1877 list_for_each_entry(q, &intel_drm_queue, list) {
1878 if (match(q->data, match_data)) {
1879 intel_drm_abort_one(q);
1880 break;
1881 }
1882 }
1883 }
1884
1885 /*
1886 * Abort by drm queue sequence number
1887 */
1888 void
intel_drm_abort_seq(ScrnInfoPtr scrn,uint32_t seq)1889 intel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq)
1890 {
1891 struct intel_drm_queue *q;
1892
1893 list_for_each_entry(q, &intel_drm_queue, list) {
1894 if (q->seq == seq) {
1895 intel_drm_abort_one(q);
1896 break;
1897 }
1898 }
1899 }
1900
1901 /*
1902 * Abort all queued entries on a specific scrn, used
1903 * when resetting the X server
1904 */
1905 static void
intel_drm_abort_scrn(ScrnInfoPtr scrn)1906 intel_drm_abort_scrn(ScrnInfoPtr scrn)
1907 {
1908 struct intel_drm_queue *q, *tmp;
1909
1910 list_for_each_entry_safe(q, tmp, &intel_drm_queue, list) {
1911 if (q->scrn == scrn)
1912 intel_drm_abort_one(q);
1913 }
1914 }
1915
pipe_select(int pipe)1916 static uint32_t pipe_select(int pipe)
1917 {
1918 if (pipe > 1)
1919 return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
1920 else if (pipe > 0)
1921 return DRM_VBLANK_SECONDARY;
1922 else
1923 return 0;
1924 }
1925
1926 /*
1927 * Get the current msc/ust value from the kernel
1928 */
1929 static int
intel_get_msc_ust(ScrnInfoPtr scrn,xf86CrtcPtr crtc,uint32_t * msc,uint64_t * ust)1930 intel_get_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint32_t *msc, uint64_t *ust)
1931 {
1932 intel_screen_private *intel = intel_get_screen_private(scrn);
1933 drmVBlank vbl;
1934
1935 /* Get current count */
1936 vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(intel_crtc_to_pipe(crtc));
1937 vbl.request.sequence = 0;
1938 vbl.request.signal = 0;
1939 if (drmWaitVBlank(intel->drmSubFD, &vbl)) {
1940 *msc = 0;
1941 *ust = 0;
1942 return BadMatch;
1943 } else {
1944 *msc = vbl.reply.sequence;
1945 *ust = (CARD64) vbl.reply.tval_sec * 1000000 + vbl.reply.tval_usec;
1946 return Success;
1947 }
1948 }
1949
1950 /*
1951 * Convert a 32-bit kernel MSC sequence number to a 64-bit local sequence
1952 * number, adding in the vblank_offset and high 32 bits, and dealing
1953 * with 64-bit wrapping
1954 */
1955 uint64_t
intel_sequence_to_crtc_msc(xf86CrtcPtr crtc,uint32_t sequence)1956 intel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence)
1957 {
1958 struct intel_crtc *intel_crtc = crtc->driver_private;
1959
1960 if ((int32_t) (sequence - intel_crtc->msc_prev) < -0x40000000)
1961 intel_crtc->msc_high += 0x100000000L;
1962 intel_crtc->msc_prev = sequence;
1963 return intel_crtc->msc_high + sequence;
1964 }
1965
1966 /*
1967 * Get the current 64-bit adjust MSC and UST value
1968 */
1969 int
intel_get_crtc_msc_ust(ScrnInfoPtr scrn,xf86CrtcPtr crtc,uint64_t * msc,uint64_t * ust)1970 intel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64_t *ust)
1971 {
1972 uint32_t sequence;
1973 int ret;
1974
1975 ret = intel_get_msc_ust(scrn, crtc, &sequence, ust);
1976 if (ret)
1977 return ret;
1978
1979 *msc = intel_sequence_to_crtc_msc(crtc, sequence);
1980 return 0;
1981 }
1982
1983 uint32_t
intel_crtc_msc_to_sequence(ScrnInfoPtr scrn,xf86CrtcPtr crtc,uint64_t expect)1984 intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect)
1985 {
1986 return (uint32_t)expect;
1987 }
1988
1989 /*
1990 * General DRM kernel handler. Looks for the matching sequence number in the
1991 * drm event queue and calls the handler for it.
1992 */
1993 static void
intel_drm_handler(int fd,uint32_t frame,uint32_t sec,uint32_t usec,void * user_ptr)1994 intel_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec, void *user_ptr)
1995 {
1996 uint32_t user_data = (intptr_t)user_ptr;
1997 struct intel_drm_queue *q;
1998
1999 list_for_each_entry(q, &intel_drm_queue, list) {
2000 if (q->seq == user_data) {
2001 list_del(&q->list);
2002 q->handler(q->scrn, q->crtc,
2003 intel_sequence_to_crtc_msc(q->crtc, frame),
2004 (uint64_t)sec * 1000000 + usec, q->data);
2005 free(q);
2006 break;
2007 }
2008 }
2009 }
2010
2011
2012 /*
2013 * Notify the page flip caller that the flip is
2014 * complete
2015 */
2016 static void
intel_pageflip_complete(struct intel_mode * mode)2017 intel_pageflip_complete(struct intel_mode *mode)
2018 {
2019 if (!mode->pageflip.handler)
2020 return;
2021
2022 /* Release framebuffer */
2023 drmModeRmFB(mode->fd, mode->old_fb_id);
2024 mode->pageflip.handler(mode->fe_msc, mode->fe_usec,
2025 mode->pageflip.data);
2026 }
2027
2028 /*
2029 * One pageflip event has completed. Update the saved msc/ust values
2030 * as needed, then check to see if the whole set of events are
2031 * complete and notify the application at that point
2032 */
2033 static struct intel_mode *
intel_handle_pageflip(struct intel_pageflip * flip,uint64_t msc,uint64_t usec)2034 intel_handle_pageflip(struct intel_pageflip *flip, uint64_t msc, uint64_t usec)
2035 {
2036 struct intel_mode *mode = flip->mode;
2037
2038 if (flip->dispatch_me) {
2039 /* Yes: Cache msc, ust for later delivery. */
2040 mode->fe_msc = msc;
2041 mode->fe_usec = usec;
2042 }
2043 free(flip);
2044
2045 /* Last crtc completed flip? */
2046 mode->flip_count--;
2047 if (mode->flip_count > 0)
2048 return NULL;
2049
2050 return mode;
2051 }
2052
2053 /*
2054 * Called from the DRM event queue when a single flip has completed
2055 */
2056 static void
intel_pageflip_handler(ScrnInfoPtr scrn,xf86CrtcPtr crtc,uint64_t msc,uint64_t usec,void * data)2057 intel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
2058 uint64_t msc, uint64_t usec, void *data)
2059 {
2060 struct intel_pageflip *flip = data;
2061 struct intel_mode *mode = intel_handle_pageflip(flip, msc, usec);
2062
2063 if (!mode)
2064 return;
2065
2066 intel_pageflip_complete(mode);
2067 }
2068
2069 /*
2070 * Called from the DRM queue abort code when a flip has been aborted
2071 */
2072 static void
intel_pageflip_abort(ScrnInfoPtr scrn,xf86CrtcPtr crtc,void * data)2073 intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data)
2074 {
2075 struct intel_pageflip *flip = data;
2076 struct intel_mode *mode = intel_handle_pageflip(flip, 0, 0);
2077
2078 if (!mode)
2079 return;
2080
2081 if (!mode->pageflip.abort)
2082 return;
2083
2084 /* Release framebuffer */
2085 drmModeRmFB(mode->fd, mode->old_fb_id);
2086 mode->pageflip.abort(mode->pageflip.data);
2087 }
2088
2089 /*
2090 * Check for pending DRM events and process them.
2091 */
2092 #if !HAVE_NOTIFY_FD
2093 static void
drm_wakeup_handler(pointer data,int err,pointer p)2094 drm_wakeup_handler(pointer data, int err, pointer p)
2095 {
2096 struct intel_mode *mode;
2097 fd_set *read_mask;
2098
2099 if (data == NULL || err < 0)
2100 return;
2101
2102 mode = data;
2103 read_mask = p;
2104 if (FD_ISSET(mode->fd, read_mask))
2105 drmHandleEvent(mode->fd, &mode->event_context);
2106 }
2107 #else
2108 static void
drm_notify_fd(int fd,int ready,void * data)2109 drm_notify_fd(int fd, int ready, void *data)
2110 {
2111 struct intel_mode *mode = data;
2112 drmHandleEvent(mode->fd, &mode->event_context);
2113 }
2114 #endif
2115
2116 /*
2117 * If there are any available, read drm_events
2118 */
2119 int
intel_mode_read_drm_events(struct intel_screen_private * intel)2120 intel_mode_read_drm_events(struct intel_screen_private *intel)
2121 {
2122 struct intel_mode *mode = intel->modes;
2123 struct pollfd p = { .fd = mode->fd, .events = POLLIN };
2124 int r;
2125
2126 do {
2127 r = poll(&p, 1, 0);
2128 } while (r == -1 && (errno == EINTR || errno == EAGAIN));
2129
2130 if (r <= 0)
2131 return 0;
2132
2133 return drmHandleEvent(mode->fd, &mode->event_context);
2134 }
2135
2136 /*
2137 * Libdrm's possible_clones is a mask of encoders, Xorg's possible_clones is a
2138 * mask of outputs. This function sets Xorg's possible_clones based on the
2139 * values read from libdrm.
2140 */
find_clones(ScrnInfoPtr scrn,xf86OutputPtr output)2141 static uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
2142 {
2143 struct intel_output *intel_output = output->driver_private, *clone_drmout;
2144 int i;
2145 xf86OutputPtr clone_output;
2146 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2147 int index_mask = 0;
2148
2149 if (intel_output->enc_clone_mask == 0)
2150 return index_mask;
2151
2152 for (i = 0; i < xf86_config->num_output; i++) {
2153 clone_output = xf86_config->output[i];
2154 clone_drmout = clone_output->driver_private;
2155 if (output == clone_output)
2156 continue;
2157
2158 if (clone_drmout->enc_mask == 0)
2159 continue;
2160 if (intel_output->enc_clone_mask == clone_drmout->enc_mask)
2161 index_mask |= (1 << i);
2162 }
2163 return index_mask;
2164 }
2165 static void
intel_compute_possible_clones(ScrnInfoPtr scrn,struct intel_mode * mode,drmModeResPtr mode_res)2166 intel_compute_possible_clones(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res)
2167 {
2168 int i, j;
2169 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2170
2171 for (i = 0; i < xf86_config->num_output; i++) {
2172 xf86OutputPtr output = xf86_config->output[i];
2173 struct intel_output *intel_output;
2174
2175 intel_output = output->driver_private;
2176 intel_output->enc_clone_mask = 0xff;
2177 /* and all the possible encoder clones for this output together */
2178 for (j = 0; j < intel_output->mode_output->count_encoders; j++)
2179 {
2180 int k;
2181 for (k = 0; k < mode_res->count_encoders; k++) {
2182 if (mode_res->encoders[k] == intel_output->mode_encoders[j]->encoder_id)
2183 intel_output->enc_mask |= (1 << k);
2184 }
2185
2186 intel_output->enc_clone_mask &= intel_output->mode_encoders[j]->possible_clones;
2187 }
2188 }
2189
2190 for (i = 0; i < xf86_config->num_output; i++) {
2191 xf86OutputPtr output = xf86_config->output[i];
2192 output->possible_clones = find_clones(scrn, output);
2193 }
2194 }
2195
intel_mode_pre_init(ScrnInfoPtr scrn,int fd,int cpp)2196 Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
2197 {
2198 intel_screen_private *intel = intel_get_screen_private(scrn);
2199 struct drm_i915_getparam gp;
2200 struct intel_mode *mode;
2201 unsigned int i;
2202 int has_flipping;
2203 drmModeResPtr mode_res;
2204
2205 mode = calloc(1, sizeof *mode);
2206 if (!mode)
2207 return FALSE;
2208
2209 mode->fd = fd;
2210
2211 list_init(&mode->crtcs);
2212 list_init(&mode->outputs);
2213
2214 xf86CrtcConfigInit(scrn, &intel_xf86crtc_config_funcs);
2215
2216 mode->cpp = cpp;
2217 mode_res = drmModeGetResources(mode->fd);
2218 if (!mode_res) {
2219 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2220 "failed to get resources: %s\n", strerror(errno));
2221 free(mode);
2222 return FALSE;
2223 }
2224
2225 xf86CrtcSetSizeRange(scrn, 320, 200, mode_res->max_width,
2226 mode_res->max_height);
2227 for (i = 0; i < mode_res->count_crtcs; i++)
2228 intel_crtc_init(scrn, mode, mode_res, i);
2229
2230 for (i = 0; i < mode_res->count_connectors; i++)
2231 intel_output_init(scrn, mode, mode_res, i, 0);
2232
2233 intel_compute_possible_clones(scrn, mode, mode_res);
2234
2235 #ifdef INTEL_PIXMAP_SHARING
2236 xf86ProviderSetup(scrn, NULL, "Intel");
2237 #endif
2238
2239 xf86InitialConfiguration(scrn, TRUE);
2240
2241 mode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
2242 mode->event_context.vblank_handler = intel_drm_handler;
2243 mode->event_context.page_flip_handler = intel_drm_handler;
2244
2245 /* XXX assumes only one intel screen */
2246 list_init(&intel_drm_queue);
2247 intel_drm_seq = 0;
2248
2249 has_flipping = 0;
2250 gp.param = I915_PARAM_HAS_PAGEFLIPPING;
2251 gp.value = &has_flipping;
2252 (void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp,
2253 sizeof(gp));
2254 if (has_flipping && intel->swapbuffers_wait) {
2255 xf86DrvMsg(scrn->scrnIndex, X_INFO,
2256 "Kernel page flipping support detected, enabling\n");
2257 intel->use_pageflipping = TRUE;
2258 }
2259
2260 intel->modes = mode;
2261 drmModeFreeResources(mode_res);
2262 return TRUE;
2263 }
2264
2265 void
intel_mode_init(struct intel_screen_private * intel)2266 intel_mode_init(struct intel_screen_private *intel)
2267 {
2268 struct intel_mode *mode = intel->modes;
2269
2270 /* We need to re-register the mode->fd for the synchronisation
2271 * feedback on every server generation, so perform the
2272 * registration within ScreenInit and not PreInit.
2273 */
2274 mode->flip_count = 0;
2275 SetNotifyFd(mode->fd, drm_notify_fd, X_NOTIFY_READ, mode);
2276 #if !HAVE_NOTIFY_FD
2277 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
2278 drm_wakeup_handler, mode);
2279 #endif
2280 }
2281
2282 void
intel_mode_remove_fb(intel_screen_private * intel)2283 intel_mode_remove_fb(intel_screen_private *intel)
2284 {
2285 struct intel_mode *mode = intel->modes;
2286
2287 if (mode->fb_id) {
2288 drmModeRmFB(mode->fd, mode->fb_id);
2289 mode->fb_id = 0;
2290 }
2291 }
2292
2293 void
intel_mode_close(intel_screen_private * intel)2294 intel_mode_close(intel_screen_private *intel)
2295 {
2296 struct intel_mode *mode = intel->modes;
2297
2298 if (mode == NULL)
2299 return;
2300
2301 intel_drm_abort_scrn(intel->scrn);
2302
2303 #if !HAVE_NOTIFY_FD
2304 RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
2305 drm_wakeup_handler, mode);
2306 #endif
2307 RemoveNotifyFd(mode->fd);
2308 }
2309
2310 void
intel_mode_fini(intel_screen_private * intel)2311 intel_mode_fini(intel_screen_private *intel)
2312 {
2313 struct intel_mode *mode = intel->modes;
2314
2315 if (mode == NULL)
2316 return;
2317
2318 while(!list_is_empty(&mode->crtcs)) {
2319 xf86CrtcDestroy(list_first_entry(&mode->crtcs,
2320 struct intel_crtc,
2321 link)->crtc);
2322 }
2323
2324 while(!list_is_empty(&mode->outputs)) {
2325 xf86OutputDestroy(list_first_entry(&mode->outputs,
2326 struct intel_output,
2327 link)->output);
2328 }
2329
2330 if (mode->fb_id)
2331 drmModeRmFB(mode->fd, mode->fb_id);
2332
2333 /* mode->rotate_fb_id should have been destroyed already */
2334
2335 free(mode);
2336 intel->modes = NULL;
2337 }
2338
2339 /* for the mode overlay */
2340 int
intel_crtc_id(xf86CrtcPtr crtc)2341 intel_crtc_id(xf86CrtcPtr crtc)
2342 {
2343 return crtc_id(crtc->driver_private);
2344 }
2345
intel_crtc_to_pipe(xf86CrtcPtr crtc)2346 int intel_crtc_to_pipe(xf86CrtcPtr crtc)
2347 {
2348 struct intel_crtc *intel_crtc = crtc->driver_private;
2349 return intel_crtc->pipe;
2350 }
2351
intel_crtc_on(xf86CrtcPtr crtc)2352 Bool intel_crtc_on(xf86CrtcPtr crtc)
2353 {
2354 struct intel_crtc *intel_crtc = crtc->driver_private;
2355 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
2356 drmModeCrtcPtr drm_crtc;
2357 Bool ret;
2358 int i;
2359
2360 if (!crtc->enabled)
2361 return FALSE;
2362
2363 /* Kernel manages CRTC status based on output config */
2364 ret = FALSE;
2365 for (i = 0; i < xf86_config->num_output; i++) {
2366 xf86OutputPtr output = xf86_config->output[i];
2367 if (output->crtc == crtc &&
2368 intel_output_dpms_status(output) == DPMSModeOn) {
2369 ret = TRUE;
2370 break;
2371 }
2372 }
2373 if (!ret)
2374 return FALSE;
2375
2376 /* And finally check with the kernel that the fb is bound */
2377 drm_crtc = drmModeGetCrtc(intel_crtc->mode->fd, crtc_id(intel_crtc));
2378 if (drm_crtc == NULL)
2379 return FALSE;
2380
2381 ret = (drm_crtc->mode_valid &&
2382 (intel_crtc->mode->fb_id == drm_crtc->buffer_id ||
2383 intel_crtc->mode->old_fb_id == drm_crtc->buffer_id));
2384 free(drm_crtc);
2385
2386 return ret;
2387 }
2388
2389
2390 static PixmapPtr
intel_create_pixmap_for_bo(ScreenPtr pScreen,dri_bo * bo,int width,int height,int depth,int bpp,int pitch)2391 intel_create_pixmap_for_bo(ScreenPtr pScreen, dri_bo *bo,
2392 int width, int height,
2393 int depth, int bpp,
2394 int pitch)
2395 {
2396 PixmapPtr pixmap;
2397
2398 pixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, 0);
2399 if (pixmap == NullPixmap)
2400 return pixmap;
2401
2402 if (!pScreen->ModifyPixmapHeader(pixmap,
2403 width, height,
2404 depth, bpp,
2405 pitch, NULL)) {
2406 pScreen->DestroyPixmap(pixmap);
2407 return NullPixmap;
2408 }
2409
2410 intel_set_pixmap_bo(pixmap, bo);
2411 return pixmap;
2412 }
2413
2414 static PixmapPtr
intel_create_pixmap_for_fbcon(ScrnInfoPtr scrn,int fbcon_id)2415 intel_create_pixmap_for_fbcon(ScrnInfoPtr scrn, int fbcon_id)
2416 {
2417 ScreenPtr pScreen = xf86ScrnToScreen(scrn);
2418 intel_screen_private *intel = intel_get_screen_private(scrn);
2419 struct intel_mode *mode = intel->modes;
2420 int fd = mode->fd;
2421 drmModeFBPtr fbcon;
2422 struct drm_gem_flink flink;
2423 drm_intel_bo *bo;
2424 PixmapPtr pixmap = NullPixmap;
2425
2426 fbcon = drmModeGetFB(fd, fbcon_id);
2427 if (fbcon == NULL)
2428 return NULL;
2429
2430 if (fbcon->depth != scrn->depth ||
2431 fbcon->width != scrn->virtualX ||
2432 fbcon->height != scrn->virtualY)
2433 goto out_free_fb;
2434
2435 flink.handle = fbcon->handle;
2436 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
2437 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2438 "Couldn't flink fbcon handle\n");
2439 goto out_free_fb;
2440 }
2441
2442 bo = drm_intel_bo_gem_create_from_name(intel->bufmgr,
2443 "fbcon", flink.name);
2444 if (bo == NULL) {
2445 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2446 "Couldn't allocate bo for fbcon handle\n");
2447 goto out_free_fb;
2448 }
2449
2450 pixmap = intel_create_pixmap_for_bo(pScreen, bo,
2451 fbcon->width, fbcon->height,
2452 fbcon->depth, fbcon->bpp,
2453 fbcon->pitch);
2454 if (pixmap == NullPixmap)
2455 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2456 "Couldn't allocate pixmap fbcon contents\n");
2457 drm_intel_bo_unreference(bo);
2458 out_free_fb:
2459 drmModeFreeFB(fbcon);
2460
2461 return pixmap;
2462 }
2463
intel_copy_fb(ScrnInfoPtr scrn)2464 void intel_copy_fb(ScrnInfoPtr scrn)
2465 {
2466 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2467 ScreenPtr pScreen = xf86ScrnToScreen(scrn);
2468 intel_screen_private *intel = intel_get_screen_private(scrn);
2469 PixmapPtr src, dst;
2470 unsigned int pitch = scrn->displayWidth * intel->cpp;
2471 struct intel_crtc *intel_crtc;
2472 int i, fbcon_id;
2473
2474 if (intel->force_fallback)
2475 return;
2476
2477 fbcon_id = 0;
2478 for (i = 0; i < xf86_config->num_crtc; i++) {
2479 intel_crtc = xf86_config->crtc[i]->driver_private;
2480 if (intel_crtc->mode_crtc->buffer_id)
2481 fbcon_id = intel_crtc->mode_crtc->buffer_id;
2482 }
2483 if (!fbcon_id)
2484 return;
2485
2486 src = intel_create_pixmap_for_fbcon(scrn, fbcon_id);
2487 if (src == NULL)
2488 return;
2489
2490 /* We dont have a screen Pixmap yet */
2491 dst = intel_create_pixmap_for_bo(pScreen, intel->front_buffer,
2492 scrn->virtualX, scrn->virtualY,
2493 scrn->depth, scrn->bitsPerPixel,
2494 pitch);
2495 if (dst == NullPixmap)
2496 goto cleanup_src;
2497
2498 if (!intel->uxa_driver->prepare_copy(src, dst,
2499 -1, -1,
2500 GXcopy, FB_ALLONES))
2501 goto cleanup_dst;
2502
2503 intel->uxa_driver->copy(dst,
2504 0, 0,
2505 0, 0,
2506 scrn->virtualX, scrn->virtualY);
2507 intel->uxa_driver->done_copy(dst);
2508 #if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(10, 0)
2509 pScreen->canDoBGNoneRoot = TRUE;
2510 #endif
2511
2512 cleanup_dst:
2513 (*pScreen->DestroyPixmap)(dst);
2514 cleanup_src:
2515 (*pScreen->DestroyPixmap)(src);
2516 }
2517
2518 void
intel_mode_hotplug(struct intel_screen_private * intel)2519 intel_mode_hotplug(struct intel_screen_private *intel)
2520 {
2521 ScrnInfoPtr scrn = intel->scrn;
2522 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2523 drmModeResPtr mode_res;
2524 int i, j;
2525 Bool found;
2526 Bool changed = FALSE;
2527
2528 mode_res = drmModeGetResources(intel->drmSubFD);
2529 if (!mode_res)
2530 goto out;
2531
2532 for (i = 0; i < config->num_output; i++) {
2533 xf86OutputPtr output = config->output[i];
2534 struct intel_output *intel_output;
2535
2536 intel_output = output->driver_private;
2537 found = FALSE;
2538 for (j = 0; j < mode_res->count_connectors; j++) {
2539 if (mode_res->connectors[j] == intel_output->output_id) {
2540 found = TRUE;
2541 break;
2542 }
2543 }
2544 if (found)
2545 continue;
2546
2547 drmModeFreeConnector(intel_output->mode_output);
2548 intel_output->mode_output = NULL;
2549 intel_output->output_id = -1;
2550 RROutputChanged(output->randr_output, TRUE);
2551
2552 changed = TRUE;
2553 }
2554
2555 /* find new output ids we don't have outputs for */
2556 for (i = 0; i < mode_res->count_connectors; i++) {
2557 found = FALSE;
2558
2559 for (j = 0; j < config->num_output; j++) {
2560 xf86OutputPtr output = config->output[j];
2561 struct intel_output *intel_output;
2562
2563 intel_output = output->driver_private;
2564 if (mode_res->connectors[i] == intel_output->output_id) {
2565 found = TRUE;
2566 break;
2567 }
2568 }
2569 if (found)
2570 continue;
2571
2572 changed = TRUE;
2573 intel_output_init(scrn, intel->modes, mode_res, i, 1);
2574 }
2575
2576 if (changed)
2577 RRTellChanged(xf86ScrnToScreen(scrn));
2578
2579 drmModeFreeResources(mode_res);
2580 out:
2581 RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
2582 }
2583
intel_box_intersect(BoxPtr dest,BoxPtr a,BoxPtr b)2584 void intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
2585 {
2586 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
2587 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
2588 if (dest->x1 >= dest->x2) {
2589 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
2590 return;
2591 }
2592
2593 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
2594 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
2595 if (dest->y1 >= dest->y2)
2596 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
2597 }
2598
intel_crtc_box(xf86CrtcPtr crtc,BoxPtr crtc_box)2599 void intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
2600 {
2601 if (crtc->enabled) {
2602 crtc_box->x1 = crtc->x;
2603 crtc_box->x2 =
2604 crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
2605 crtc_box->y1 = crtc->y;
2606 crtc_box->y2 =
2607 crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
2608 } else
2609 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
2610 }
2611
intel_box_area(BoxPtr box)2612 static int intel_box_area(BoxPtr box)
2613 {
2614 return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
2615 }
2616
2617 /*
2618 * Return the crtc covering 'box'. If two crtcs cover a portion of
2619 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
2620 * with greater coverage
2621 */
2622
2623 xf86CrtcPtr
intel_covering_crtc(ScrnInfoPtr scrn,BoxPtr box,xf86CrtcPtr desired,BoxPtr crtc_box_ret)2624 intel_covering_crtc(ScrnInfoPtr scrn,
2625 BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
2626 {
2627 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2628 xf86CrtcPtr crtc, best_crtc;
2629 int coverage, best_coverage;
2630 int c;
2631 BoxRec crtc_box, cover_box;
2632
2633 best_crtc = NULL;
2634 best_coverage = 0;
2635 crtc_box_ret->x1 = 0;
2636 crtc_box_ret->x2 = 0;
2637 crtc_box_ret->y1 = 0;
2638 crtc_box_ret->y2 = 0;
2639 for (c = 0; c < xf86_config->num_crtc; c++) {
2640 crtc = xf86_config->crtc[c];
2641
2642 /* If the CRTC is off, treat it as not covering */
2643 if (!intel_crtc_on(crtc))
2644 continue;
2645
2646 intel_crtc_box(crtc, &crtc_box);
2647 intel_box_intersect(&cover_box, &crtc_box, box);
2648 coverage = intel_box_area(&cover_box);
2649 if (coverage && crtc == desired) {
2650 *crtc_box_ret = crtc_box;
2651 return crtc;
2652 }
2653 if (coverage > best_coverage) {
2654 *crtc_box_ret = crtc_box;
2655 best_crtc = crtc;
2656 best_coverage = coverage;
2657 }
2658 }
2659 return best_crtc;
2660 }
2661