Initial code release
[adaptation/xorg-x11-drv-intel.git] / src / intel_display.c
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 <fcntl.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <poll.h>
38
39 #include "xorgVersion.h"
40
41 #include "intel.h"
42 #include "intel_bufmgr.h"
43 #include "xf86drmMode.h"
44 #include "X11/Xatom.h"
45
46 struct intel_mode {
47         int fd;
48         uint32_t fb_id;
49         drmModeResPtr mode_res;
50         int cpp;
51
52         drmEventContext event_context;
53         DRI2FrameEventPtr flip_info;
54         int old_fb_id;
55         int flip_count;
56         unsigned int fe_frame;
57         unsigned int fe_tv_sec;
58         unsigned int fe_tv_usec;
59
60         struct list outputs;
61         struct list crtcs;
62 };
63
64 struct intel_pageflip {
65         struct intel_mode *mode;
66         Bool dispatch_me;
67 };
68
69 struct intel_crtc {
70         struct intel_mode *mode;
71         drmModeModeInfo kmode;
72         drmModeCrtcPtr mode_crtc;
73         int pipe;
74         dri_bo *cursor;
75         dri_bo *rotate_bo;
76         uint32_t rotate_pitch;
77         uint32_t rotate_fb_id;
78         xf86CrtcPtr crtc;
79         struct list link;
80 };
81
82 struct intel_property {
83         drmModePropertyPtr mode_prop;
84         uint64_t value;
85         int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */
86         Atom *atoms;
87 };
88
89 struct intel_output {
90         struct intel_mode *mode;
91         int output_id;
92         drmModeConnectorPtr mode_output;
93         drmModeEncoderPtr mode_encoder;
94         int num_props;
95         struct intel_property *props;
96         void *private_data;
97
98         Bool has_panel_limits;
99         int panel_hdisplay;
100         int panel_vdisplay;
101
102         int dpms_mode;
103         const char *backlight_iface;
104         int backlight_active_level;
105         int backlight_max;
106         xf86OutputPtr output;
107         struct list link;
108 };
109
110 static void
111 intel_output_dpms(xf86OutputPtr output, int mode);
112
113 static void
114 intel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode);
115
116 #define BACKLIGHT_CLASS "/sys/class/backlight"
117
118 /*
119  * List of available kernel interfaces in priority order
120  */
121 static const char *backlight_interfaces[] = {
122         "asus-laptop",
123         "eeepc",
124         "thinkpad_screen",
125         "mbp_backlight",
126         "fujitsu-laptop",
127         "sony",
128         "samsung",
129         "acpi_video1", /* finally fallback to the generic acpi drivers */
130         "acpi_video0",
131         "intel_backlight",
132         NULL,
133 };
134 /*
135  * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table +
136  * '/' + "max_backlight"
137  */
138 #define BACKLIGHT_PATH_LEN 80
139 /* Enough for 10 digits of backlight + '\n' + '\0' */
140 #define BACKLIGHT_VALUE_LEN 12
141
142 static inline int
143 crtc_id(struct intel_crtc *crtc)
144 {
145         return crtc->mode_crtc->crtc_id;
146 }
147
148 static void
149 intel_output_backlight_set(xf86OutputPtr output, int level)
150 {
151         struct intel_output *intel_output = output->driver_private;
152         char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
153         int fd, len, ret;
154
155         if (level > intel_output->backlight_max)
156                 level = intel_output->backlight_max;
157         if (! intel_output->backlight_iface || level < 0)
158                 return;
159
160         len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level);
161         sprintf(path, "%s/%s/brightness",
162                 BACKLIGHT_CLASS, intel_output->backlight_iface);
163         fd = open(path, O_RDWR);
164         if (fd == -1) {
165                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s for backlight "
166                            "control: %s\n", path, strerror(errno));
167                 return;
168         }
169
170         ret = write(fd, val, len);
171         if (ret == -1) {
172                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "write to %s for backlight "
173                            "control failed: %s\n", path, strerror(errno));
174         }
175
176         close(fd);
177 }
178
179 static int
180 intel_output_backlight_get(xf86OutputPtr output)
181 {
182         struct intel_output *intel_output = output->driver_private;
183         char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
184         int fd, level;
185
186         sprintf(path, "%s/%s/actual_brightness",
187                 BACKLIGHT_CLASS, intel_output->backlight_iface);
188         fd = open(path, O_RDONLY);
189         if (fd == -1) {
190                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s "
191                            "for backlight control: %s\n", path, strerror(errno));
192                 return -1;
193         }
194
195         memset(val, 0, sizeof(val));
196         if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) {
197                 close(fd);
198                 return -1;
199         }
200
201         close(fd);
202
203         level = atoi(val);
204         if (level > intel_output->backlight_max)
205                 level = intel_output->backlight_max;
206         if (level < 0)
207                 level = -1;
208         return level;
209 }
210
211 static int
212 intel_output_backlight_get_max(xf86OutputPtr output)
213 {
214         struct intel_output *intel_output = output->driver_private;
215         char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
216         int fd, max = 0;
217
218         sprintf(path, "%s/%s/max_brightness",
219                 BACKLIGHT_CLASS, intel_output->backlight_iface);
220         fd = open(path, O_RDONLY);
221         if (fd == -1) {
222                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s "
223                            "for backlight control: %s\n", path, strerror(errno));
224                 return -1;
225         }
226
227         memset(val, 0, sizeof(val));
228         if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) {
229                 close(fd);
230                 return -1;
231         }
232
233         close(fd);
234
235         max = atoi(val);
236         if (max <= 0)
237                 max = -1;
238         return max;
239 }
240
241 static void
242 intel_output_backlight_init(xf86OutputPtr output)
243 {
244         struct intel_output *intel_output = output->driver_private;
245         int i;
246
247         for (i = 0; backlight_interfaces[i] != NULL; i++) {
248                 char path[BACKLIGHT_PATH_LEN];
249                 struct stat buf;
250
251                 sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]);
252                 if (!stat(path, &buf)) {
253                         intel_output->backlight_iface = backlight_interfaces[i];
254                         intel_output->backlight_max = intel_output_backlight_get_max(output);
255                         if (intel_output->backlight_max > 0) {
256                                 intel_output->backlight_active_level = intel_output_backlight_get(output);
257                                 xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
258                                            "found backlight control interface %s\n", path);
259                                 return;
260                         }
261                 }
262         }
263         intel_output->backlight_iface = NULL;
264 }
265
266
267 static void
268 mode_from_kmode(ScrnInfoPtr scrn,
269                 drmModeModeInfoPtr kmode,
270                 DisplayModePtr  mode)
271 {
272         memset(mode, 0, sizeof(DisplayModeRec));
273         mode->status = MODE_OK;
274
275         mode->Clock = kmode->clock;
276
277         mode->HDisplay = kmode->hdisplay;
278         mode->HSyncStart = kmode->hsync_start;
279         mode->HSyncEnd = kmode->hsync_end;
280         mode->HTotal = kmode->htotal;
281         mode->HSkew = kmode->hskew;
282
283         mode->VDisplay = kmode->vdisplay;
284         mode->VSyncStart = kmode->vsync_start;
285         mode->VSyncEnd = kmode->vsync_end;
286         mode->VTotal = kmode->vtotal;
287         mode->VScan = kmode->vscan;
288
289         mode->Flags = kmode->flags; //& FLAG_BITS;
290         mode->name = strdup(kmode->name);
291
292         if (kmode->type & DRM_MODE_TYPE_DRIVER)
293                 mode->type = M_T_DRIVER;
294         if (kmode->type & DRM_MODE_TYPE_PREFERRED)
295                 mode->type |= M_T_PREFERRED;
296
297         xf86SetModeCrtc (mode, scrn->adjustFlags);
298 }
299
300 static void
301 mode_to_kmode(ScrnInfoPtr scrn,
302               drmModeModeInfoPtr kmode,
303               DisplayModePtr mode)
304 {
305         memset(kmode, 0, sizeof(*kmode));
306
307         kmode->clock = mode->Clock;
308         kmode->hdisplay = mode->HDisplay;
309         kmode->hsync_start = mode->HSyncStart;
310         kmode->hsync_end = mode->HSyncEnd;
311         kmode->htotal = mode->HTotal;
312         kmode->hskew = mode->HSkew;
313
314         kmode->vdisplay = mode->VDisplay;
315         kmode->vsync_start = mode->VSyncStart;
316         kmode->vsync_end = mode->VSyncEnd;
317         kmode->vtotal = mode->VTotal;
318         kmode->vscan = mode->VScan;
319
320         kmode->flags = mode->Flags; //& FLAG_BITS;
321         if (mode->name)
322                 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
323         kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
324 }
325
326 static void
327 intel_crtc_dpms(xf86CrtcPtr intel_crtc, int mode)
328 {
329
330 }
331
332 static Bool
333 intel_crtc_apply(xf86CrtcPtr crtc)
334 {
335         ScrnInfoPtr scrn = crtc->scrn;
336         struct intel_crtc *intel_crtc = crtc->driver_private;
337         struct intel_mode *mode = intel_crtc->mode;
338         xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
339         uint32_t *output_ids;
340         int output_count = 0;
341         int fb_id, x, y;
342         int i, ret = FALSE;
343
344         output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
345         if (!output_ids)
346                 return FALSE;
347
348         for (i = 0; i < xf86_config->num_output; i++) {
349                 xf86OutputPtr output = xf86_config->output[i];
350                 struct intel_output *intel_output;
351
352                 if (output->crtc != crtc)
353                         continue;
354
355                 intel_output = output->driver_private;
356                 output_ids[output_count] =
357                         intel_output->mode_output->connector_id;
358                 output_count++;
359         }
360
361 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0)
362         if (!xf86CrtcRotate(crtc, mode, rotation))
363                 goto done;
364 #else
365         if (!xf86CrtcRotate(crtc))
366                 goto done;
367 #endif
368
369 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0)
370         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
371                                crtc->gamma_blue, crtc->gamma_size);
372 #endif
373
374         x = crtc->x;
375         y = crtc->y;
376         fb_id = mode->fb_id;
377         if (intel_crtc->rotate_fb_id) {
378                 fb_id = intel_crtc->rotate_fb_id;
379                 x = 0;
380                 y = 0;
381         }
382         ret = drmModeSetCrtc(mode->fd, crtc_id(intel_crtc),
383                              fb_id, x, y, output_ids, output_count,
384                              &intel_crtc->kmode);
385         if (ret) {
386                 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
387                            "failed to set mode: %s\n", strerror(-ret));
388                 ret = FALSE;
389         } else {
390                 ret = TRUE;
391
392                 /* Force DPMS to On for all outputs, which the kernel will have done
393                  * with the mode set. Also, restore the backlight level
394                  */
395                 for (i = 0; i < xf86_config->num_output; i++) {
396                     xf86OutputPtr output = xf86_config->output[i];
397                     struct intel_output *intel_output;
398
399                     if (output->crtc != crtc)
400                         continue;
401
402                     intel_output = output->driver_private;
403                     intel_output_dpms_backlight(output, intel_output->dpms_mode, DPMSModeOn);
404                     intel_output->dpms_mode = DPMSModeOn;
405                 }
406         }
407
408         intel_set_gem_max_sizes(scrn);
409
410         if (scrn->pScreen)
411                 xf86_reload_cursors(scrn->pScreen);
412
413 done:
414         free(output_ids);
415         return ret;
416 }
417
418 static Bool
419 intel_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
420                           Rotation rotation, int x, int y)
421 {
422         ScrnInfoPtr scrn = crtc->scrn;
423         intel_screen_private *intel = intel_get_screen_private(scrn);
424         struct intel_crtc *intel_crtc = crtc->driver_private;
425         struct intel_mode *intel_mode = intel_crtc->mode;
426         int saved_x, saved_y;
427         Rotation saved_rotation;
428         DisplayModeRec saved_mode;
429         int ret = TRUE;
430         unsigned int pitch = scrn->displayWidth * intel->cpp;
431
432         if (intel_mode->fb_id == 0) {
433                 ret = drmModeAddFB(intel_mode->fd,
434                                    scrn->virtualX, scrn->virtualY,
435                                    scrn->depth, scrn->bitsPerPixel,
436                                    pitch, intel->front_buffer->handle,
437                                    &intel_mode->fb_id);
438                 if (ret < 0) {
439                         ErrorF("failed to add fb\n");
440                         return FALSE;
441                 }
442         }
443
444         saved_mode = crtc->mode;
445         saved_x = crtc->x;
446         saved_y = crtc->y;
447         saved_rotation = crtc->rotation;
448
449         crtc->mode = *mode;
450         crtc->x = x;
451         crtc->y = y;
452         crtc->rotation = rotation;
453
454         intel_batch_submit(crtc->scrn);
455
456         mode_to_kmode(crtc->scrn, &intel_crtc->kmode, mode);
457         ret = intel_crtc_apply(crtc);
458         if (!ret) {
459                 crtc->x = saved_x;
460                 crtc->y = saved_y;
461                 crtc->rotation = saved_rotation;
462                 crtc->mode = saved_mode;
463         }
464         return ret;
465 }
466
467 static void
468 intel_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
469 {
470
471 }
472
473 static void
474 intel_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
475 {
476         struct intel_crtc *intel_crtc = crtc->driver_private;
477         struct intel_mode *mode = intel_crtc->mode;
478
479         drmModeMoveCursor(mode->fd, crtc_id(intel_crtc), x, y);
480 }
481
482 static void
483 intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
484 {
485         struct intel_crtc *intel_crtc = crtc->driver_private;
486         int ret;
487
488         ret = dri_bo_subdata(intel_crtc->cursor, 0, 64*64*4, image);
489         if (ret)
490                 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
491                            "failed to set cursor: %s\n", strerror(-ret));
492 }
493
494 static void
495 intel_crtc_hide_cursor(xf86CrtcPtr crtc)
496 {
497         struct intel_crtc *intel_crtc = crtc->driver_private;
498         struct intel_mode *mode = intel_crtc->mode;
499
500         drmModeSetCursor(mode->fd, crtc_id(intel_crtc), 0, 64, 64);
501 }
502
503 static void
504 intel_crtc_show_cursor(xf86CrtcPtr crtc)
505 {
506         struct intel_crtc *intel_crtc = crtc->driver_private;
507         struct intel_mode *mode = intel_crtc->mode;
508
509         drmModeSetCursor(mode->fd, crtc_id(intel_crtc),
510                          intel_crtc->cursor->handle, 64, 64);
511 }
512
513 static void *
514 intel_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
515 {
516         ScrnInfoPtr scrn = crtc->scrn;
517         struct intel_crtc *intel_crtc = crtc->driver_private;
518         struct intel_mode *mode = intel_crtc->mode;
519         unsigned long rotate_pitch;
520         uint32_t tiling;
521         int ret;
522
523         intel_crtc->rotate_bo = intel_allocate_framebuffer(scrn,
524                                                              width, height,
525                                                              mode->cpp,
526                                                              &rotate_pitch,
527                                                              &tiling);
528
529         if (!intel_crtc->rotate_bo) {
530                 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
531                            "Couldn't allocate shadow memory for rotated CRTC\n");
532                 return NULL;
533         }
534
535         ret = drmModeAddFB(mode->fd, width, height, crtc->scrn->depth,
536                            crtc->scrn->bitsPerPixel, rotate_pitch,
537                            intel_crtc->rotate_bo->handle,
538                            &intel_crtc->rotate_fb_id);
539         if (ret) {
540                 ErrorF("failed to add rotate fb\n");
541                 drm_intel_bo_unreference(intel_crtc->rotate_bo);
542                 return NULL;
543         }
544
545         intel_crtc->rotate_pitch = rotate_pitch;
546         return intel_crtc->rotate_bo;
547 }
548
549 static PixmapPtr
550 intel_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
551 {
552         ScrnInfoPtr scrn = crtc->scrn;
553         intel_screen_private *intel = intel_get_screen_private(scrn);
554         struct intel_crtc *intel_crtc = crtc->driver_private;
555         PixmapPtr rotate_pixmap;
556
557         if (!data) {
558                 data = intel_crtc_shadow_allocate (crtc, width, height);
559                 if (!data) {
560                         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
561                                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
562                         return NULL;
563                 }
564         }
565         if (intel_crtc->rotate_bo == NULL) {
566                 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
567                            "Couldn't allocate shadow pixmap for rotated CRTC\n");
568                 return NULL;
569         }
570
571         rotate_pixmap = GetScratchPixmapHeader(scrn->pScreen,
572                                                width, height,
573                                                scrn->depth,
574                                                scrn->bitsPerPixel,
575                                                intel_crtc->rotate_pitch,
576                                                NULL);
577
578         if (rotate_pixmap == NULL) {
579                 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
580                            "Couldn't allocate shadow pixmap for rotated CRTC\n");
581                 return NULL;
582         }
583
584         intel_set_pixmap_bo(rotate_pixmap, intel_crtc->rotate_bo);
585
586         intel->shadow_present = TRUE;
587
588         return rotate_pixmap;
589 }
590
591 static void
592 intel_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
593 {
594         ScrnInfoPtr scrn = crtc->scrn;
595         intel_screen_private *intel = intel_get_screen_private(scrn);
596         struct intel_crtc *intel_crtc = crtc->driver_private;
597         struct intel_mode *mode = intel_crtc->mode;
598
599         if (rotate_pixmap) {
600                 intel_set_pixmap_bo(rotate_pixmap, NULL);
601                 FreeScratchPixmapHeader(rotate_pixmap);
602         }
603
604         if (data) {
605                 /* Be sure to sync acceleration before the memory gets
606                  * unbound. */
607                 drmModeRmFB(mode->fd, intel_crtc->rotate_fb_id);
608                 intel_crtc->rotate_fb_id = 0;
609
610                 dri_bo_unreference(intel_crtc->rotate_bo);
611                 intel_crtc->rotate_bo = NULL;
612         }
613
614         intel->shadow_present = intel->use_shadow;
615 }
616
617 static void
618 intel_crtc_gamma_set(xf86CrtcPtr crtc,
619                        CARD16 *red, CARD16 *green, CARD16 *blue, int size)
620 {
621         struct intel_crtc *intel_crtc = crtc->driver_private;
622         struct intel_mode *mode = intel_crtc->mode;
623
624         drmModeCrtcSetGamma(mode->fd, crtc_id(intel_crtc),
625                             size, red, green, blue);
626 }
627
628 static void
629 intel_crtc_destroy(xf86CrtcPtr crtc)
630 {
631         struct intel_crtc *intel_crtc = crtc->driver_private;
632
633         if (intel_crtc->cursor) {
634                 drmModeSetCursor(intel_crtc->mode->fd, crtc_id(intel_crtc), 0, 64, 64);
635                 drm_intel_bo_unreference(intel_crtc->cursor);
636                 intel_crtc->cursor = NULL;
637         }
638
639         list_del(&intel_crtc->link);
640         free(intel_crtc);
641
642         crtc->driver_private = NULL;
643 }
644
645 static const xf86CrtcFuncsRec intel_crtc_funcs = {
646         .dpms = intel_crtc_dpms,
647         .set_mode_major = intel_crtc_set_mode_major,
648         .set_cursor_colors = intel_crtc_set_cursor_colors,
649         .set_cursor_position = intel_crtc_set_cursor_position,
650         .show_cursor = intel_crtc_show_cursor,
651         .hide_cursor = intel_crtc_hide_cursor,
652         .load_cursor_argb = intel_crtc_load_cursor_argb,
653         .shadow_create = intel_crtc_shadow_create,
654         .shadow_allocate = intel_crtc_shadow_allocate,
655         .shadow_destroy = intel_crtc_shadow_destroy,
656         .gamma_set = intel_crtc_gamma_set,
657         .destroy = intel_crtc_destroy,
658 };
659
660 static void
661 intel_crtc_init(ScrnInfoPtr scrn, struct intel_mode *mode, int num)
662 {
663         intel_screen_private *intel = intel_get_screen_private(scrn);
664         xf86CrtcPtr crtc;
665         struct intel_crtc *intel_crtc;
666
667         intel_crtc = calloc(sizeof(struct intel_crtc), 1);
668         if (intel_crtc == NULL)
669                 return;
670
671         crtc = xf86CrtcCreate(scrn, &intel_crtc_funcs);
672         if (crtc == NULL) {
673                 free(intel_crtc);
674                 return;
675         }
676
677         intel_crtc->mode_crtc = drmModeGetCrtc(mode->fd,
678                                                mode->mode_res->crtcs[num]);
679         intel_crtc->mode = mode;
680         crtc->driver_private = intel_crtc;
681
682         intel_crtc->pipe = drm_intel_get_pipe_from_crtc_id(intel->bufmgr,
683                                                            crtc_id(intel_crtc));
684
685         intel_crtc->cursor = drm_intel_bo_alloc(intel->bufmgr, "ARGB cursor",
686                                                 HWCURSOR_SIZE_ARGB,
687                                                 GTT_PAGE_SIZE);
688
689         intel_crtc->crtc = crtc;
690         list_add(&intel_crtc->link, &mode->crtcs);
691 }
692
693 static Bool
694 is_panel(int type)
695 {
696         return (type == DRM_MODE_CONNECTOR_LVDS ||
697                 type == DRM_MODE_CONNECTOR_eDP);
698 }
699
700 static xf86OutputStatus
701 intel_output_detect(xf86OutputPtr output)
702 {
703         /* go to the hw and retrieve a new output struct */
704         struct intel_output *intel_output = output->driver_private;
705         struct intel_mode *mode = intel_output->mode;
706         xf86OutputStatus status;
707
708         drmModeFreeConnector(intel_output->mode_output);
709         intel_output->mode_output =
710                 drmModeGetConnector(mode->fd, intel_output->output_id);
711
712         switch (intel_output->mode_output->connection) {
713         case DRM_MODE_CONNECTED:
714                 status = XF86OutputStatusConnected;
715                 break;
716         case DRM_MODE_DISCONNECTED:
717                 status = XF86OutputStatusDisconnected;
718                 break;
719         default:
720         case DRM_MODE_UNKNOWNCONNECTION:
721                 status = XF86OutputStatusUnknown;
722                 break;
723         }
724         return status;
725 }
726
727 static Bool
728 intel_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
729 {
730         struct intel_output *intel_output = output->driver_private;
731
732         /*
733          * If the connector type is a panel, we will use the panel limit to
734          * verfiy whether the mode is valid.
735          */
736         if (intel_output->has_panel_limits) {
737                 if (pModes->HDisplay > intel_output->panel_hdisplay ||
738                     pModes->VDisplay > intel_output->panel_vdisplay)
739                         return MODE_PANEL;
740         }
741
742         return MODE_OK;
743 }
744
745 static void
746 intel_output_attach_edid(xf86OutputPtr output)
747 {
748         struct intel_output *intel_output = output->driver_private;
749         drmModeConnectorPtr koutput = intel_output->mode_output;
750         struct intel_mode *mode = intel_output->mode;
751         drmModePropertyBlobPtr edid_blob = NULL;
752         xf86MonPtr mon = NULL;
753         int i;
754
755         /* look for an EDID property */
756         for (i = 0; i < koutput->count_props; i++) {
757                 drmModePropertyPtr props;
758
759                 props = drmModeGetProperty(mode->fd, koutput->props[i]);
760                 if (!props)
761                         continue;
762
763                 if (!(props->flags & DRM_MODE_PROP_BLOB)) {
764                         drmModeFreeProperty(props);
765                         continue;
766                 }
767
768                 if (!strcmp(props->name, "EDID")) {
769                         drmModeFreePropertyBlob(edid_blob);
770                         edid_blob =
771                                 drmModeGetPropertyBlob(mode->fd,
772                                                        koutput->prop_values[i]);
773                 }
774                 drmModeFreeProperty(props);
775         }
776
777         if (edid_blob) {
778                 mon = xf86InterpretEDID(output->scrn->scrnIndex,
779                                         edid_blob->data);
780
781                 if (mon && edid_blob->length > 128)
782                         mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
783         }
784
785         xf86OutputSetEDID(output, mon);
786
787         if (edid_blob)
788                 drmModeFreePropertyBlob(edid_blob);
789 }
790
791 static DisplayModePtr
792 intel_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
793 {
794         xf86MonPtr mon = output->MonInfo;
795
796         if (!mon || !GTF_SUPPORTED(mon->features.msc)) {
797                 DisplayModePtr i, m, p = NULL;
798                 int max_x = 0, max_y = 0;
799                 float max_vrefresh = 0.0;
800
801                 for (m = modes; m; m = m->next) {
802                         if (m->type & M_T_PREFERRED)
803                                 p = m;
804                         max_x = max(max_x, m->HDisplay);
805                         max_y = max(max_y, m->VDisplay);
806                         max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
807                 }
808
809                 max_vrefresh = max(max_vrefresh, 60.0);
810                 max_vrefresh *= (1 + SYNC_TOLERANCE);
811
812 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0)
813                 m = xf86GetDefaultModes();
814 #else
815                 m = xf86GetDefaultModes(0,0);
816 #endif
817
818                 xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
819
820                 for (i = m; i; i = i->next) {
821                         if (xf86ModeVRefresh(i) > max_vrefresh)
822                                 i->status = MODE_VSYNC;
823                         if (p && i->HDisplay >= p->HDisplay &&
824                             i->VDisplay >= p->VDisplay &&
825                             xf86ModeVRefresh(i) >= xf86ModeVRefresh(p))
826                                 i->status = MODE_VSYNC;
827                 }
828
829                 xf86PruneInvalidModes(output->scrn, &m, FALSE);
830
831                 modes = xf86ModesAdd(modes, m);
832         }
833
834         return modes;
835 }
836
837 static DisplayModePtr
838 intel_output_get_modes(xf86OutputPtr output)
839 {
840         struct intel_output *intel_output = output->driver_private;
841         drmModeConnectorPtr koutput = intel_output->mode_output;
842         DisplayModePtr Modes = NULL;
843         int i;
844
845         intel_output_attach_edid(output);
846
847         /* modes should already be available */
848         for (i = 0; i < koutput->count_modes; i++) {
849                 DisplayModePtr Mode;
850
851                 Mode = calloc(1, sizeof(DisplayModeRec));
852                 if (Mode) {
853                         mode_from_kmode(output->scrn, &koutput->modes[i], Mode);
854                         Modes = xf86ModesAdd(Modes, Mode);
855                 }
856         }
857
858         /*
859          * If the connector type is a panel, we will traverse the kernel mode to
860          * get the panel limit. And then add all the standard modes to fake
861          * the fullscreen experience.
862          * If it is incorrect, please fix me.
863          */
864         intel_output->has_panel_limits = FALSE;
865         if (is_panel(koutput->connector_type)) {
866                 for (i = 0; i < koutput->count_modes; i++) {
867                         drmModeModeInfo *mode_ptr;
868
869                         mode_ptr = &koutput->modes[i];
870                         if (mode_ptr->hdisplay > intel_output->panel_hdisplay)
871                                 intel_output->panel_hdisplay = mode_ptr->hdisplay;
872                         if (mode_ptr->vdisplay > intel_output->panel_vdisplay)
873                                 intel_output->panel_vdisplay = mode_ptr->vdisplay;
874                 }
875
876                 intel_output->has_panel_limits =
877                         intel_output->panel_hdisplay &&
878                         intel_output->panel_vdisplay;
879
880                 Modes = intel_output_panel_edid(output, Modes);
881         }
882
883         return Modes;
884 }
885
886 static void
887 intel_output_destroy(xf86OutputPtr output)
888 {
889         struct intel_output *intel_output = output->driver_private;
890         int i;
891
892         for (i = 0; i < intel_output->num_props; i++) {
893                 drmModeFreeProperty(intel_output->props[i].mode_prop);
894                 free(intel_output->props[i].atoms);
895         }
896         free(intel_output->props);
897
898         drmModeFreeConnector(intel_output->mode_output);
899         intel_output->mode_output = NULL;
900
901         list_del(&intel_output->link);
902         free(intel_output);
903
904         output->driver_private = NULL;
905 }
906
907 static void
908 intel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode)
909 {
910         struct intel_output *intel_output = output->driver_private;
911
912         if (!intel_output->backlight_iface)
913                 return;
914
915         if (mode == DPMSModeOn) {
916                 /* If we're going from off->on we may need to turn on the backlight. */
917                 if (oldmode != DPMSModeOn)
918                         intel_output_backlight_set(output,
919                                                    intel_output->backlight_active_level);
920         } else {
921                 /* Only save the current backlight value if we're going from on to off. */
922                 if (oldmode == DPMSModeOn)
923                         intel_output->backlight_active_level = intel_output_backlight_get(output);
924                 intel_output_backlight_set(output, 0);
925         }
926 }
927
928 static void
929 intel_output_dpms(xf86OutputPtr output, int dpms)
930 {
931         struct intel_output *intel_output = output->driver_private;
932         drmModeConnectorPtr koutput = intel_output->mode_output;
933         struct intel_mode *mode = intel_output->mode;
934         int i;
935
936         for (i = 0; i < koutput->count_props; i++) {
937                 drmModePropertyPtr props;
938
939                 props = drmModeGetProperty(mode->fd, koutput->props[i]);
940                 if (!props)
941                         continue;
942
943                 if (!strcmp(props->name, "DPMS")) {
944                         drmModeConnectorSetProperty(mode->fd,
945                                                     intel_output->output_id,
946                                                     props->prop_id,
947                                                     dpms);
948                         intel_output_dpms_backlight(output,
949                                                       intel_output->dpms_mode,
950                                                       dpms);
951                         intel_output->dpms_mode = dpms;
952                         drmModeFreeProperty(props);
953                         return;
954                 }
955
956                 drmModeFreeProperty(props);
957         }
958 }
959
960 int
961 intel_output_dpms_status(xf86OutputPtr output)
962 {
963         struct intel_output *intel_output = output->driver_private;
964         return intel_output->dpms_mode;
965 }
966
967 static Bool
968 intel_property_ignore(drmModePropertyPtr prop)
969 {
970         if (!prop)
971                 return TRUE;
972
973         /* ignore blob prop */
974         if (prop->flags & DRM_MODE_PROP_BLOB)
975                 return TRUE;
976
977         /* ignore standard property */
978         if (!strcmp(prop->name, "EDID") ||
979             !strcmp(prop->name, "DPMS"))
980                 return TRUE;
981
982         return FALSE;
983 }
984
985 #define BACKLIGHT_NAME             "Backlight"
986 #define BACKLIGHT_DEPRECATED_NAME  "BACKLIGHT"
987 static Atom backlight_atom, backlight_deprecated_atom;
988
989 static void
990 intel_output_create_resources(xf86OutputPtr output)
991 {
992         struct intel_output *intel_output = output->driver_private;
993         drmModeConnectorPtr mode_output = intel_output->mode_output;
994         struct intel_mode *mode = intel_output->mode;
995         int i, j, err;
996
997         intel_output->props = calloc(mode_output->count_props,
998                                      sizeof(struct intel_property));
999         if (!intel_output->props)
1000                 return;
1001
1002         intel_output->num_props = 0;
1003         for (i = j = 0; i < mode_output->count_props; i++) {
1004                 drmModePropertyPtr drmmode_prop;
1005
1006                 drmmode_prop = drmModeGetProperty(mode->fd,
1007                                                   mode_output->props[i]);
1008                 if (intel_property_ignore(drmmode_prop)) {
1009                         drmModeFreeProperty(drmmode_prop);
1010                         continue;
1011                 }
1012
1013                 intel_output->props[j].mode_prop = drmmode_prop;
1014                 intel_output->props[j].value = mode_output->prop_values[i];
1015                 j++;
1016         }
1017         intel_output->num_props = j;
1018
1019         for (i = 0; i < intel_output->num_props; i++) {
1020                 struct intel_property *p = &intel_output->props[i];
1021                 drmModePropertyPtr drmmode_prop = p->mode_prop;
1022
1023                 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1024                         INT32 range[2];
1025
1026                         p->num_atoms = 1;
1027                         p->atoms = calloc(p->num_atoms, sizeof(Atom));
1028                         if (!p->atoms)
1029                                 continue;
1030
1031                         p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1032                         range[0] = drmmode_prop->values[0];
1033                         range[1] = drmmode_prop->values[1];
1034                         err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1035                                                         FALSE, TRUE,
1036                                                         drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1037                                                         2, range);
1038                         if (err != 0) {
1039                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1040                                            "RRConfigureOutputProperty error, %d\n", err);
1041                         }
1042                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1043                                                      XA_INTEGER, 32, PropModeReplace, 1, &p->value, FALSE, TRUE);
1044                         if (err != 0) {
1045                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1046                                            "RRChangeOutputProperty error, %d\n", err);
1047                         }
1048                 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1049                         p->num_atoms = drmmode_prop->count_enums + 1;
1050                         p->atoms = calloc(p->num_atoms, sizeof(Atom));
1051                         if (!p->atoms)
1052                                 continue;
1053
1054                         p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1055                         for (j = 1; j <= drmmode_prop->count_enums; j++) {
1056                                 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
1057                                 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
1058                         }
1059
1060                         err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1061                                                         FALSE, FALSE,
1062                                                         drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1063                                                         p->num_atoms - 1, (INT32 *)&p->atoms[1]);
1064                         if (err != 0) {
1065                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1066                                            "RRConfigureOutputProperty error, %d\n", err);
1067                         }
1068
1069                         for (j = 0; j < drmmode_prop->count_enums; j++)
1070                                 if (drmmode_prop->enums[j].value == p->value)
1071                                         break;
1072                         /* there's always a matching value */
1073                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1074                                                      XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
1075                         if (err != 0) {
1076                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1077                                            "RRChangeOutputProperty error, %d\n", err);
1078                         }
1079                 }
1080         }
1081
1082         if (intel_output->backlight_iface) {
1083                 INT32 data, backlight_range[2];
1084
1085                 /* Set up the backlight property, which takes effect
1086                  * immediately and accepts values only within the
1087                  * backlight_range.
1088                  */
1089                 backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1, TRUE);
1090                 backlight_deprecated_atom = MakeAtom(BACKLIGHT_DEPRECATED_NAME,
1091                                                      sizeof(BACKLIGHT_DEPRECATED_NAME) - 1, TRUE);
1092
1093                 backlight_range[0] = 0;
1094                 backlight_range[1] = intel_output->backlight_max;
1095                 err = RRConfigureOutputProperty(output->randr_output,
1096                                                 backlight_atom,
1097                                                 FALSE, TRUE, FALSE,
1098                                                 2, backlight_range);
1099                 if (err != 0) {
1100                         xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1101                                    "RRConfigureOutputProperty error, %d\n", err);
1102                 }
1103                 err = RRConfigureOutputProperty(output->randr_output,
1104                                                 backlight_deprecated_atom,
1105                                                 FALSE, TRUE, FALSE,
1106                                                 2, backlight_range);
1107                 if (err != 0) {
1108                         xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1109                                    "RRConfigureOutputProperty error, %d\n", err);
1110                 }
1111                 /* Set the current value of the backlight property */
1112                 data = intel_output->backlight_active_level;
1113                 err = RRChangeOutputProperty(output->randr_output, backlight_atom,
1114                                              XA_INTEGER, 32, PropModeReplace, 1, &data,
1115                                              FALSE, TRUE);
1116                 if (err != 0) {
1117                         xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1118                                    "RRChangeOutputProperty error, %d\n", err);
1119                 }
1120                 err = RRChangeOutputProperty(output->randr_output, backlight_deprecated_atom,
1121                                              XA_INTEGER, 32, PropModeReplace, 1, &data,
1122                                              FALSE, TRUE);
1123                 if (err != 0) {
1124                         xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1125                                    "RRChangeOutputProperty error, %d\n", err);
1126                 }
1127         }
1128 }
1129
1130 static Bool
1131 intel_output_set_property(xf86OutputPtr output, Atom property,
1132                             RRPropertyValuePtr value)
1133 {
1134         struct intel_output *intel_output = output->driver_private;
1135         struct intel_mode *mode = intel_output->mode;
1136         int i;
1137
1138         if (property == backlight_atom || property == backlight_deprecated_atom) {
1139                 INT32 val;
1140
1141                 if (value->type != XA_INTEGER || value->format != 32 ||
1142                     value->size != 1)
1143                 {
1144                         return FALSE;
1145                 }
1146
1147                 val = *(INT32 *)value->data;
1148                 if (val < 0 || val > intel_output->backlight_max)
1149                         return FALSE;
1150
1151                 if (intel_output->dpms_mode == DPMSModeOn)
1152                         intel_output_backlight_set(output, val);
1153                 intel_output->backlight_active_level = val;
1154                 return TRUE;
1155         }
1156
1157         for (i = 0; i < intel_output->num_props; i++) {
1158                 struct intel_property *p = &intel_output->props[i];
1159
1160                 if (p->atoms[0] != property)
1161                         continue;
1162
1163                 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1164                         uint32_t val;
1165
1166                         if (value->type != XA_INTEGER || value->format != 32 ||
1167                             value->size != 1)
1168                                 return FALSE;
1169                         val = *(uint32_t *)value->data;
1170
1171                         drmModeConnectorSetProperty(mode->fd, intel_output->output_id,
1172                                                     p->mode_prop->prop_id, (uint64_t)val);
1173                         return TRUE;
1174                 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1175                         Atom    atom;
1176                         const char      *name;
1177                         int             j;
1178
1179                         if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
1180                                 return FALSE;
1181                         memcpy(&atom, value->data, 4);
1182                         name = NameForAtom(atom);
1183
1184                         /* search for matching name string, then set its value down */
1185                         for (j = 0; j < p->mode_prop->count_enums; j++) {
1186                                 if (!strcmp(p->mode_prop->enums[j].name, name)) {
1187                                         drmModeConnectorSetProperty(mode->fd, intel_output->output_id,
1188                                                                     p->mode_prop->prop_id, p->mode_prop->enums[j].value);
1189                                         return TRUE;
1190                                 }
1191                         }
1192                         return FALSE;
1193                 }
1194         }
1195
1196         /* We didn't recognise this property, just report success in order
1197          * to allow the set to continue, otherwise we break setting of
1198          * common properties like EDID.
1199          */
1200         return TRUE;
1201 }
1202
1203 static Bool
1204 intel_output_get_property(xf86OutputPtr output, Atom property)
1205 {
1206         struct intel_output *intel_output = output->driver_private;
1207         int err;
1208
1209         if (property == backlight_atom || property == backlight_deprecated_atom) {
1210                 INT32 val;
1211
1212                 if (! intel_output->backlight_iface)
1213                         return FALSE;
1214
1215                 val = intel_output_backlight_get(output);
1216                 if (val < 0)
1217                         return FALSE;
1218
1219                 err = RRChangeOutputProperty(output->randr_output, property,
1220                                              XA_INTEGER, 32, PropModeReplace, 1, &val,
1221                                              FALSE, TRUE);
1222                 if (err != 0) {
1223                         xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1224                                    "RRChangeOutputProperty error, %d\n", err);
1225                         return FALSE;
1226                 }
1227
1228                 return TRUE;
1229         }
1230
1231         return FALSE;
1232 }
1233
1234 static const xf86OutputFuncsRec intel_output_funcs = {
1235         .create_resources = intel_output_create_resources,
1236 #ifdef RANDR_12_INTERFACE
1237         .set_property = intel_output_set_property,
1238         .get_property = intel_output_get_property,
1239 #endif
1240         .dpms = intel_output_dpms,
1241 #if 0
1242
1243         .save = drmmode_crt_save,
1244         .restore = drmmode_crt_restore,
1245         .mode_fixup = drmmode_crt_mode_fixup,
1246         .prepare = intel_output_prepare,
1247         .mode_set = drmmode_crt_mode_set,
1248         .commit = intel_output_commit,
1249 #endif
1250         .detect = intel_output_detect,
1251         .mode_valid = intel_output_mode_valid,
1252
1253         .get_modes = intel_output_get_modes,
1254         .destroy = intel_output_destroy
1255 };
1256
1257 static const int subpixel_conv_table[7] = {
1258         0,
1259         SubPixelUnknown,
1260         SubPixelHorizontalRGB,
1261         SubPixelHorizontalBGR,
1262         SubPixelVerticalRGB,
1263         SubPixelVerticalBGR,
1264         SubPixelNone
1265 };
1266
1267 static const char *output_names[] = {
1268         "None",
1269         "VGA",
1270         "DVI",
1271         "DVI",
1272         "DVI",
1273         "Composite",
1274         "TV",
1275         "LVDS",
1276         "CTV",
1277         "DIN",
1278         "DP",
1279         "HDMI",
1280         "HDMI",
1281         "TV",
1282         "eDP",
1283 };
1284
1285 static void
1286 intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, int num)
1287 {
1288         xf86OutputPtr output;
1289         drmModeConnectorPtr koutput;
1290         drmModeEncoderPtr kencoder;
1291         struct intel_output *intel_output;
1292         const char *output_name;
1293         char name[32];
1294
1295         koutput = drmModeGetConnector(mode->fd,
1296                                       mode->mode_res->connectors[num]);
1297         if (!koutput)
1298                 return;
1299
1300         kencoder = drmModeGetEncoder(mode->fd, koutput->encoders[0]);
1301         if (!kencoder) {
1302                 drmModeFreeConnector(koutput);
1303                 return;
1304         }
1305
1306         if (koutput->connector_type < ARRAY_SIZE(output_names))
1307                 output_name = output_names[koutput->connector_type];
1308         else
1309                 output_name = "UNKNOWN";
1310         snprintf(name, 32, "%s%d", output_name, koutput->connector_type_id);
1311
1312         output = xf86OutputCreate (scrn, &intel_output_funcs, name);
1313         if (!output) {
1314                 drmModeFreeEncoder(kencoder);
1315                 drmModeFreeConnector(koutput);
1316                 return;
1317         }
1318
1319         intel_output = calloc(sizeof(struct intel_output), 1);
1320         if (!intel_output) {
1321                 xf86OutputDestroy(output);
1322                 drmModeFreeConnector(koutput);
1323                 drmModeFreeEncoder(kencoder);
1324                 return;
1325         }
1326
1327         intel_output->output_id = mode->mode_res->connectors[num];
1328         intel_output->mode_output = koutput;
1329         intel_output->mode_encoder = kencoder;
1330         intel_output->mode = mode;
1331
1332         output->mm_width = koutput->mmWidth;
1333         output->mm_height = koutput->mmHeight;
1334
1335         output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1336         output->driver_private = intel_output;
1337
1338         if (is_panel(koutput->connector_type))
1339                 intel_output_backlight_init(output);
1340
1341         output->possible_crtcs = kencoder->possible_crtcs;
1342         output->possible_clones = kencoder->possible_clones;
1343         output->interlaceAllowed = TRUE;
1344
1345         intel_output->output = output;
1346         list_add(&intel_output->link, &mode->outputs);
1347 }
1348
1349 static Bool
1350 intel_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
1351 {
1352         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1353         struct intel_crtc *intel_crtc = xf86_config->crtc[0]->driver_private;
1354         struct intel_mode *mode = intel_crtc->mode;
1355         intel_screen_private *intel = intel_get_screen_private(scrn);
1356         drm_intel_bo *old_front = NULL;
1357         Bool        ret;
1358         uint32_t    old_fb_id;
1359         int         i, old_width, old_height, old_pitch;
1360         unsigned long pitch;
1361         uint32_t tiling;
1362
1363         if (scrn->virtualX == width && scrn->virtualY == height)
1364                 return TRUE;
1365
1366         intel_batch_submit(scrn);
1367
1368         old_width = scrn->virtualX;
1369         old_height = scrn->virtualY;
1370         old_pitch = scrn->displayWidth;
1371         old_fb_id = mode->fb_id;
1372         old_front = intel->front_buffer;
1373
1374         intel->front_buffer = intel_allocate_framebuffer(scrn,
1375                                                          width, height,
1376                                                          intel->cpp,
1377                                                          &pitch,
1378                                                          &tiling);
1379         if (!intel->front_buffer)
1380                 goto fail;
1381
1382         ret = drmModeAddFB(mode->fd, width, height, scrn->depth,
1383                            scrn->bitsPerPixel, pitch,
1384                            intel->front_buffer->handle,
1385                            &mode->fb_id);
1386         if (ret)
1387                 goto fail;
1388
1389         intel->front_pitch = pitch;
1390         intel->front_tiling = tiling;
1391
1392         scrn->virtualX = width;
1393         scrn->virtualY = height;
1394
1395         for (i = 0; i < xf86_config->num_crtc; i++) {
1396                 xf86CrtcPtr crtc = xf86_config->crtc[i];
1397
1398                 if (!crtc->enabled)
1399                         continue;
1400
1401                 if (!intel_crtc_apply(crtc))
1402                         goto fail;
1403         }
1404
1405         intel_uxa_create_screen_resources(scrn->pScreen);
1406
1407         if (old_fb_id)
1408                 drmModeRmFB(mode->fd, old_fb_id);
1409         if (old_front)
1410                 drm_intel_bo_unreference(old_front);
1411
1412         return TRUE;
1413
1414 fail:
1415         if (intel->front_buffer)
1416                 drm_intel_bo_unreference(intel->front_buffer);
1417         intel->front_buffer = old_front;
1418         scrn->virtualX = old_width;
1419         scrn->virtualY = old_height;
1420         scrn->displayWidth = old_pitch;
1421         if (old_fb_id != mode->fb_id)
1422                 drmModeRmFB(mode->fd, mode->fb_id);
1423         mode->fb_id = old_fb_id;
1424
1425         return FALSE;
1426 }
1427
1428 Bool
1429 intel_do_pageflip(intel_screen_private *intel,
1430                   dri_bo *new_front,
1431                   DRI2FrameEventPtr flip_info, int ref_crtc_hw_id)
1432 {
1433         ScrnInfoPtr scrn = intel->scrn;
1434         xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1435         struct intel_crtc *crtc = config->crtc[0]->driver_private;
1436         struct intel_mode *mode = crtc->mode;
1437         unsigned int pitch = scrn->displayWidth * intel->cpp;
1438         struct intel_pageflip *flip;
1439         int i, old_fb_id;
1440
1441         /*
1442          * Create a new handle for the back buffer
1443          */
1444         old_fb_id = mode->fb_id;
1445         if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
1446                          scrn->depth, scrn->bitsPerPixel, pitch,
1447                          new_front->handle, &mode->fb_id))
1448                 goto error_out;
1449
1450         /*
1451          * Queue flips on all enabled CRTCs
1452          * Note that if/when we get per-CRTC buffers, we'll have to update this.
1453          * Right now it assumes a single shared fb across all CRTCs, with the
1454          * kernel fixing up the offset of each CRTC as necessary.
1455          *
1456          * Also, flips queued on disabled or incorrectly configured displays
1457          * may never complete; this is a configuration error.
1458          */
1459         mode->fe_frame = 0;
1460         mode->fe_tv_sec = 0;
1461         mode->fe_tv_usec = 0;
1462
1463         for (i = 0; i < config->num_crtc; i++) {
1464                 if (!config->crtc[i]->enabled)
1465                         continue;
1466
1467                 mode->flip_info = flip_info;
1468                 mode->flip_count++;
1469
1470                 crtc = config->crtc[i]->driver_private;
1471
1472                 flip = calloc(1, sizeof(struct intel_pageflip));
1473                 if (flip == NULL) {
1474                         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1475                                    "flip queue: carrier alloc failed.\n");
1476                         goto error_undo;
1477                 }
1478
1479                 /* Only the reference crtc will finally deliver its page flip
1480                  * completion event. All other crtc's events will be discarded.
1481                  */
1482                 flip->dispatch_me = (intel_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id);
1483                 flip->mode = mode;
1484
1485                 if (drmModePageFlip(mode->fd,
1486                                     crtc_id(crtc),
1487                                     mode->fb_id,
1488                                     DRM_MODE_PAGE_FLIP_EVENT, flip)) {
1489                         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1490                                    "flip queue failed: %s\n", strerror(errno));
1491                         free(flip);
1492                         goto error_undo;
1493                 }
1494         }
1495
1496         mode->old_fb_id = old_fb_id;
1497         return TRUE;
1498
1499 error_undo:
1500         drmModeRmFB(mode->fd, mode->fb_id);
1501         mode->fb_id = old_fb_id;
1502
1503 error_out:
1504         xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
1505                    strerror(errno));
1506         return FALSE;
1507 }
1508
1509 static const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = {
1510         intel_xf86crtc_resize
1511 };
1512
1513 static void
1514 intel_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
1515                        unsigned int tv_usec, void *event)
1516 {
1517         I830DRI2FrameEventHandler(frame, tv_sec, tv_usec, event);
1518 }
1519
1520 static void
1521 intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
1522                           unsigned int tv_usec, void *event_data)
1523 {
1524         struct intel_pageflip *flip = event_data;
1525         struct intel_mode *mode = flip->mode;
1526
1527         /* Is this the event whose info shall be delivered to higher level? */
1528         if (flip->dispatch_me) {
1529                 /* Yes: Cache msc, ust for later delivery. */
1530                 mode->fe_frame = frame;
1531                 mode->fe_tv_sec = tv_sec;
1532                 mode->fe_tv_usec = tv_usec;
1533         }
1534         free(flip);
1535
1536         /* Last crtc completed flip? */
1537         mode->flip_count--;
1538         if (mode->flip_count > 0)
1539                 return;
1540
1541         /* Release framebuffer */
1542         drmModeRmFB(mode->fd, mode->old_fb_id);
1543
1544         if (mode->flip_info == NULL)
1545                 return;
1546
1547         /* Deliver cached msc, ust from reference crtc to flip event handler */
1548         I830DRI2FlipEventHandler(mode->fe_frame, mode->fe_tv_sec,
1549                                  mode->fe_tv_usec, mode->flip_info);
1550 }
1551
1552 static void
1553 drm_wakeup_handler(pointer data, int err, pointer p)
1554 {
1555         struct intel_mode *mode;
1556         fd_set *read_mask;
1557
1558         if (data == NULL || err < 0)
1559                 return;
1560
1561         mode = data;
1562         read_mask = p;
1563         if (FD_ISSET(mode->fd, read_mask))
1564                 drmHandleEvent(mode->fd, &mode->event_context);
1565 }
1566
1567 Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
1568 {
1569         intel_screen_private *intel = intel_get_screen_private(scrn);
1570         struct drm_i915_getparam gp;
1571         struct intel_mode *mode;
1572         unsigned int i;
1573         int has_flipping;
1574
1575         mode = calloc(1, sizeof *mode);
1576         if (!mode)
1577                 return FALSE;
1578
1579         mode->fd = fd;
1580
1581         list_init(&mode->crtcs);
1582         list_init(&mode->outputs);
1583
1584         xf86CrtcConfigInit(scrn, &intel_xf86crtc_config_funcs);
1585
1586         mode->cpp = cpp;
1587         mode->mode_res = drmModeGetResources(mode->fd);
1588         if (!mode->mode_res) {
1589                 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1590                            "failed to get resources: %s\n", strerror(errno));
1591                 free(mode);
1592                 return FALSE;
1593         }
1594
1595         xf86CrtcSetSizeRange(scrn, 320, 200, mode->mode_res->max_width,
1596                              mode->mode_res->max_height);
1597         for (i = 0; i < mode->mode_res->count_crtcs; i++)
1598                 intel_crtc_init(scrn, mode, i);
1599
1600         for (i = 0; i < mode->mode_res->count_connectors; i++)
1601                 intel_output_init(scrn, mode, i);
1602
1603         xf86InitialConfiguration(scrn, TRUE);
1604
1605         has_flipping = 0;
1606         gp.param = I915_PARAM_HAS_PAGEFLIPPING;
1607         gp.value = &has_flipping;
1608         (void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp,
1609                                   sizeof(gp));
1610         if (has_flipping) {
1611                 xf86DrvMsg(scrn->scrnIndex, X_INFO,
1612                            "Kernel page flipping support detected, enabling\n");
1613                 intel->use_pageflipping = TRUE;
1614
1615                 mode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
1616                 mode->event_context.vblank_handler = intel_vblank_handler;
1617                 mode->event_context.page_flip_handler = intel_page_flip_handler;
1618         }
1619
1620         intel->modes = mode;
1621         return TRUE;
1622 }
1623
1624 void
1625 intel_mode_init(struct intel_screen_private *intel)
1626 {
1627         if (intel->use_pageflipping) {
1628                 struct intel_mode *mode = intel->modes;
1629
1630                 /* We need to re-register the mode->fd for the synchronisation
1631                  * feedback on every server generation, so perform the
1632                  * registration within ScreenInit and not PreInit.
1633                  */
1634                 mode->flip_count = 0;
1635                 AddGeneralSocket(mode->fd);
1636                 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1637                                                drm_wakeup_handler, mode);
1638         }
1639 }
1640
1641 void
1642 intel_mode_remove_fb(intel_screen_private *intel)
1643 {
1644         struct intel_mode *mode = intel->modes;
1645
1646         if (mode->fb_id) {
1647                 drmModeRmFB(mode->fd, mode->fb_id);
1648                 mode->fb_id = 0;
1649         }
1650 }
1651
1652 void
1653 intel_mode_fini(intel_screen_private *intel)
1654 {
1655         struct intel_mode *mode = intel->modes;
1656
1657         while(!list_is_empty(&mode->crtcs)) {
1658                 xf86CrtcDestroy(list_first_entry(&mode->crtcs,
1659                                                  struct intel_crtc,
1660                                                  link)->crtc);
1661         }
1662
1663         while(!list_is_empty(&mode->outputs)) {
1664                 xf86OutputDestroy(list_first_entry(&mode->outputs,
1665                                                    struct intel_output,
1666                                                    link)->output);
1667         }
1668
1669         if (mode->fb_id)
1670                 drmModeRmFB(mode->fd, mode->fb_id);
1671
1672         /* mode->rotate_fb_id should have been destroyed already */
1673
1674         free(mode);
1675         intel->modes = NULL;
1676 }
1677
1678 /* for the mode overlay */
1679 int
1680 intel_crtc_id(xf86CrtcPtr crtc)
1681 {
1682         return crtc_id(crtc->driver_private);
1683 }
1684
1685 int intel_crtc_to_pipe(xf86CrtcPtr crtc)
1686 {
1687         struct intel_crtc *intel_crtc = crtc->driver_private;
1688         return intel_crtc->pipe;
1689 }