2 * Copyright © 2007 Red Hat, Inc.
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:
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
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
24 * Dave Airlie <airlied@redhat.com>
32 #include <sys/types.h>
39 #include "xorgVersion.h"
42 #include "intel_bufmgr.h"
43 #include "xf86drmMode.h"
44 #include "X11/Xatom.h"
49 drmModeResPtr mode_res;
52 drmEventContext event_context;
53 DRI2FrameEventPtr flip_info;
56 unsigned int fe_frame;
57 unsigned int fe_tv_sec;
58 unsigned int fe_tv_usec;
64 struct intel_pageflip {
65 struct intel_mode *mode;
70 struct intel_mode *mode;
71 drmModeModeInfo kmode;
72 drmModeCrtcPtr mode_crtc;
76 uint32_t rotate_pitch;
77 uint32_t rotate_fb_id;
82 struct intel_property {
83 drmModePropertyPtr mode_prop;
85 int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */
90 struct intel_mode *mode;
92 drmModeConnectorPtr mode_output;
93 drmModeEncoderPtr mode_encoder;
95 struct intel_property *props;
98 Bool has_panel_limits;
103 const char *backlight_iface;
104 int backlight_active_level;
106 xf86OutputPtr output;
111 intel_output_dpms(xf86OutputPtr output, int mode);
114 intel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode);
116 #define BACKLIGHT_CLASS "/sys/class/backlight"
119 * List of available kernel interfaces in priority order
121 static const char *backlight_interfaces[] = {
129 "acpi_video1", /* finally fallback to the generic acpi drivers */
135 * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table +
136 * '/' + "max_backlight"
138 #define BACKLIGHT_PATH_LEN 80
139 /* Enough for 10 digits of backlight + '\n' + '\0' */
140 #define BACKLIGHT_VALUE_LEN 12
143 crtc_id(struct intel_crtc *crtc)
145 return crtc->mode_crtc->crtc_id;
149 intel_output_backlight_set(xf86OutputPtr output, int level)
151 struct intel_output *intel_output = output->driver_private;
152 char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
155 if (level > intel_output->backlight_max)
156 level = intel_output->backlight_max;
157 if (! intel_output->backlight_iface || level < 0)
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);
165 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s for backlight "
166 "control: %s\n", path, strerror(errno));
170 ret = write(fd, val, len);
172 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "write to %s for backlight "
173 "control failed: %s\n", path, strerror(errno));
180 intel_output_backlight_get(xf86OutputPtr output)
182 struct intel_output *intel_output = output->driver_private;
183 char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
186 sprintf(path, "%s/%s/actual_brightness",
187 BACKLIGHT_CLASS, intel_output->backlight_iface);
188 fd = open(path, O_RDONLY);
190 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s "
191 "for backlight control: %s\n", path, strerror(errno));
195 memset(val, 0, sizeof(val));
196 if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) {
204 if (level > intel_output->backlight_max)
205 level = intel_output->backlight_max;
212 intel_output_backlight_get_max(xf86OutputPtr output)
214 struct intel_output *intel_output = output->driver_private;
215 char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
218 sprintf(path, "%s/%s/max_brightness",
219 BACKLIGHT_CLASS, intel_output->backlight_iface);
220 fd = open(path, O_RDONLY);
222 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s "
223 "for backlight control: %s\n", path, strerror(errno));
227 memset(val, 0, sizeof(val));
228 if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) {
242 intel_output_backlight_init(xf86OutputPtr output)
244 struct intel_output *intel_output = output->driver_private;
247 for (i = 0; backlight_interfaces[i] != NULL; i++) {
248 char path[BACKLIGHT_PATH_LEN];
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);
263 intel_output->backlight_iface = NULL;
268 mode_from_kmode(ScrnInfoPtr scrn,
269 drmModeModeInfoPtr kmode,
272 memset(mode, 0, sizeof(DisplayModeRec));
273 mode->status = MODE_OK;
275 mode->Clock = kmode->clock;
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;
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;
289 mode->Flags = kmode->flags; //& FLAG_BITS;
290 mode->name = strdup(kmode->name);
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;
297 xf86SetModeCrtc (mode, scrn->adjustFlags);
301 mode_to_kmode(ScrnInfoPtr scrn,
302 drmModeModeInfoPtr kmode,
305 memset(kmode, 0, sizeof(*kmode));
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;
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;
320 kmode->flags = mode->Flags; //& FLAG_BITS;
322 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
323 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
327 intel_crtc_dpms(xf86CrtcPtr intel_crtc, int mode)
333 intel_crtc_apply(xf86CrtcPtr crtc)
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;
344 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
348 for (i = 0; i < xf86_config->num_output; i++) {
349 xf86OutputPtr output = xf86_config->output[i];
350 struct intel_output *intel_output;
352 if (output->crtc != crtc)
355 intel_output = output->driver_private;
356 output_ids[output_count] =
357 intel_output->mode_output->connector_id;
361 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0)
362 if (!xf86CrtcRotate(crtc, mode, rotation))
365 if (!xf86CrtcRotate(crtc))
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);
377 if (intel_crtc->rotate_fb_id) {
378 fb_id = intel_crtc->rotate_fb_id;
382 ret = drmModeSetCrtc(mode->fd, crtc_id(intel_crtc),
383 fb_id, x, y, output_ids, output_count,
386 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
387 "failed to set mode: %s\n", strerror(-ret));
392 /* Force DPMS to On for all outputs, which the kernel will have done
393 * with the mode set. Also, restore the backlight level
395 for (i = 0; i < xf86_config->num_output; i++) {
396 xf86OutputPtr output = xf86_config->output[i];
397 struct intel_output *intel_output;
399 if (output->crtc != crtc)
402 intel_output = output->driver_private;
403 intel_output_dpms_backlight(output, intel_output->dpms_mode, DPMSModeOn);
404 intel_output->dpms_mode = DPMSModeOn;
408 intel_set_gem_max_sizes(scrn);
411 xf86_reload_cursors(scrn->pScreen);
419 intel_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
420 Rotation rotation, int x, int y)
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;
430 unsigned int pitch = scrn->displayWidth * intel->cpp;
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,
439 ErrorF("failed to add fb\n");
444 saved_mode = crtc->mode;
447 saved_rotation = crtc->rotation;
452 crtc->rotation = rotation;
454 intel_batch_submit(crtc->scrn);
456 mode_to_kmode(crtc->scrn, &intel_crtc->kmode, mode);
457 ret = intel_crtc_apply(crtc);
461 crtc->rotation = saved_rotation;
462 crtc->mode = saved_mode;
468 intel_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
474 intel_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
476 struct intel_crtc *intel_crtc = crtc->driver_private;
477 struct intel_mode *mode = intel_crtc->mode;
479 drmModeMoveCursor(mode->fd, crtc_id(intel_crtc), x, y);
483 intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
485 struct intel_crtc *intel_crtc = crtc->driver_private;
488 ret = dri_bo_subdata(intel_crtc->cursor, 0, 64*64*4, image);
490 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
491 "failed to set cursor: %s\n", strerror(-ret));
495 intel_crtc_hide_cursor(xf86CrtcPtr crtc)
497 struct intel_crtc *intel_crtc = crtc->driver_private;
498 struct intel_mode *mode = intel_crtc->mode;
500 drmModeSetCursor(mode->fd, crtc_id(intel_crtc), 0, 64, 64);
504 intel_crtc_show_cursor(xf86CrtcPtr crtc)
506 struct intel_crtc *intel_crtc = crtc->driver_private;
507 struct intel_mode *mode = intel_crtc->mode;
509 drmModeSetCursor(mode->fd, crtc_id(intel_crtc),
510 intel_crtc->cursor->handle, 64, 64);
514 intel_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
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;
523 intel_crtc->rotate_bo = intel_allocate_framebuffer(scrn,
529 if (!intel_crtc->rotate_bo) {
530 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
531 "Couldn't allocate shadow memory for rotated CRTC\n");
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);
540 ErrorF("failed to add rotate fb\n");
541 drm_intel_bo_unreference(intel_crtc->rotate_bo);
545 intel_crtc->rotate_pitch = rotate_pitch;
546 return intel_crtc->rotate_bo;
550 intel_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
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;
558 data = intel_crtc_shadow_allocate (crtc, width, height);
560 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
561 "Couldn't allocate shadow pixmap for rotated CRTC\n");
565 if (intel_crtc->rotate_bo == NULL) {
566 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
567 "Couldn't allocate shadow pixmap for rotated CRTC\n");
571 rotate_pixmap = GetScratchPixmapHeader(scrn->pScreen,
575 intel_crtc->rotate_pitch,
578 if (rotate_pixmap == NULL) {
579 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
580 "Couldn't allocate shadow pixmap for rotated CRTC\n");
584 intel_set_pixmap_bo(rotate_pixmap, intel_crtc->rotate_bo);
586 intel->shadow_present = TRUE;
588 return rotate_pixmap;
592 intel_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
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;
600 intel_set_pixmap_bo(rotate_pixmap, NULL);
601 FreeScratchPixmapHeader(rotate_pixmap);
605 /* Be sure to sync acceleration before the memory gets
607 drmModeRmFB(mode->fd, intel_crtc->rotate_fb_id);
608 intel_crtc->rotate_fb_id = 0;
610 dri_bo_unreference(intel_crtc->rotate_bo);
611 intel_crtc->rotate_bo = NULL;
614 intel->shadow_present = intel->use_shadow;
618 intel_crtc_gamma_set(xf86CrtcPtr crtc,
619 CARD16 *red, CARD16 *green, CARD16 *blue, int size)
621 struct intel_crtc *intel_crtc = crtc->driver_private;
622 struct intel_mode *mode = intel_crtc->mode;
624 drmModeCrtcSetGamma(mode->fd, crtc_id(intel_crtc),
625 size, red, green, blue);
629 intel_crtc_destroy(xf86CrtcPtr crtc)
631 struct intel_crtc *intel_crtc = crtc->driver_private;
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;
639 list_del(&intel_crtc->link);
642 crtc->driver_private = NULL;
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,
661 intel_crtc_init(ScrnInfoPtr scrn, struct intel_mode *mode, int num)
663 intel_screen_private *intel = intel_get_screen_private(scrn);
665 struct intel_crtc *intel_crtc;
667 intel_crtc = calloc(sizeof(struct intel_crtc), 1);
668 if (intel_crtc == NULL)
671 crtc = xf86CrtcCreate(scrn, &intel_crtc_funcs);
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;
682 intel_crtc->pipe = drm_intel_get_pipe_from_crtc_id(intel->bufmgr,
683 crtc_id(intel_crtc));
685 intel_crtc->cursor = drm_intel_bo_alloc(intel->bufmgr, "ARGB cursor",
689 intel_crtc->crtc = crtc;
690 list_add(&intel_crtc->link, &mode->crtcs);
696 return (type == DRM_MODE_CONNECTOR_LVDS ||
697 type == DRM_MODE_CONNECTOR_eDP);
700 static xf86OutputStatus
701 intel_output_detect(xf86OutputPtr output)
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;
708 drmModeFreeConnector(intel_output->mode_output);
709 intel_output->mode_output =
710 drmModeGetConnector(mode->fd, intel_output->output_id);
712 switch (intel_output->mode_output->connection) {
713 case DRM_MODE_CONNECTED:
714 status = XF86OutputStatusConnected;
716 case DRM_MODE_DISCONNECTED:
717 status = XF86OutputStatusDisconnected;
720 case DRM_MODE_UNKNOWNCONNECTION:
721 status = XF86OutputStatusUnknown;
728 intel_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
730 struct intel_output *intel_output = output->driver_private;
733 * If the connector type is a panel, we will use the panel limit to
734 * verfiy whether the mode is valid.
736 if (intel_output->has_panel_limits) {
737 if (pModes->HDisplay > intel_output->panel_hdisplay ||
738 pModes->VDisplay > intel_output->panel_vdisplay)
746 intel_output_attach_edid(xf86OutputPtr output)
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;
755 /* look for an EDID property */
756 for (i = 0; i < koutput->count_props; i++) {
757 drmModePropertyPtr props;
759 props = drmModeGetProperty(mode->fd, koutput->props[i]);
763 if (!(props->flags & DRM_MODE_PROP_BLOB)) {
764 drmModeFreeProperty(props);
768 if (!strcmp(props->name, "EDID")) {
769 drmModeFreePropertyBlob(edid_blob);
771 drmModeGetPropertyBlob(mode->fd,
772 koutput->prop_values[i]);
774 drmModeFreeProperty(props);
778 mon = xf86InterpretEDID(output->scrn->scrnIndex,
781 if (mon && edid_blob->length > 128)
782 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
785 xf86OutputSetEDID(output, mon);
788 drmModeFreePropertyBlob(edid_blob);
791 static DisplayModePtr
792 intel_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
794 xf86MonPtr mon = output->MonInfo;
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;
801 for (m = modes; m; m = m->next) {
802 if (m->type & M_T_PREFERRED)
804 max_x = max(max_x, m->HDisplay);
805 max_y = max(max_y, m->VDisplay);
806 max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
809 max_vrefresh = max(max_vrefresh, 60.0);
810 max_vrefresh *= (1 + SYNC_TOLERANCE);
812 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0)
813 m = xf86GetDefaultModes();
815 m = xf86GetDefaultModes(0,0);
818 xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
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;
829 xf86PruneInvalidModes(output->scrn, &m, FALSE);
831 modes = xf86ModesAdd(modes, m);
837 static DisplayModePtr
838 intel_output_get_modes(xf86OutputPtr output)
840 struct intel_output *intel_output = output->driver_private;
841 drmModeConnectorPtr koutput = intel_output->mode_output;
842 DisplayModePtr Modes = NULL;
845 intel_output_attach_edid(output);
847 /* modes should already be available */
848 for (i = 0; i < koutput->count_modes; i++) {
851 Mode = calloc(1, sizeof(DisplayModeRec));
853 mode_from_kmode(output->scrn, &koutput->modes[i], Mode);
854 Modes = xf86ModesAdd(Modes, Mode);
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.
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;
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;
876 intel_output->has_panel_limits =
877 intel_output->panel_hdisplay &&
878 intel_output->panel_vdisplay;
880 Modes = intel_output_panel_edid(output, Modes);
887 intel_output_destroy(xf86OutputPtr output)
889 struct intel_output *intel_output = output->driver_private;
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);
896 free(intel_output->props);
898 drmModeFreeConnector(intel_output->mode_output);
899 intel_output->mode_output = NULL;
901 list_del(&intel_output->link);
904 output->driver_private = NULL;
908 intel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode)
910 struct intel_output *intel_output = output->driver_private;
912 if (!intel_output->backlight_iface)
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);
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);
929 intel_output_dpms(xf86OutputPtr output, int dpms)
931 struct intel_output *intel_output = output->driver_private;
932 drmModeConnectorPtr koutput = intel_output->mode_output;
933 struct intel_mode *mode = intel_output->mode;
936 for (i = 0; i < koutput->count_props; i++) {
937 drmModePropertyPtr props;
939 props = drmModeGetProperty(mode->fd, koutput->props[i]);
943 if (!strcmp(props->name, "DPMS")) {
944 drmModeConnectorSetProperty(mode->fd,
945 intel_output->output_id,
948 intel_output_dpms_backlight(output,
949 intel_output->dpms_mode,
951 intel_output->dpms_mode = dpms;
952 drmModeFreeProperty(props);
956 drmModeFreeProperty(props);
961 intel_output_dpms_status(xf86OutputPtr output)
963 struct intel_output *intel_output = output->driver_private;
964 return intel_output->dpms_mode;
968 intel_property_ignore(drmModePropertyPtr prop)
973 /* ignore blob prop */
974 if (prop->flags & DRM_MODE_PROP_BLOB)
977 /* ignore standard property */
978 if (!strcmp(prop->name, "EDID") ||
979 !strcmp(prop->name, "DPMS"))
985 #define BACKLIGHT_NAME "Backlight"
986 #define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT"
987 static Atom backlight_atom, backlight_deprecated_atom;
990 intel_output_create_resources(xf86OutputPtr output)
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;
997 intel_output->props = calloc(mode_output->count_props,
998 sizeof(struct intel_property));
999 if (!intel_output->props)
1002 intel_output->num_props = 0;
1003 for (i = j = 0; i < mode_output->count_props; i++) {
1004 drmModePropertyPtr drmmode_prop;
1006 drmmode_prop = drmModeGetProperty(mode->fd,
1007 mode_output->props[i]);
1008 if (intel_property_ignore(drmmode_prop)) {
1009 drmModeFreeProperty(drmmode_prop);
1013 intel_output->props[j].mode_prop = drmmode_prop;
1014 intel_output->props[j].value = mode_output->prop_values[i];
1017 intel_output->num_props = j;
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;
1023 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1027 p->atoms = calloc(p->num_atoms, sizeof(Atom));
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],
1036 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1039 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1040 "RRConfigureOutputProperty error, %d\n", err);
1042 err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1043 XA_INTEGER, 32, PropModeReplace, 1, &p->value, FALSE, TRUE);
1045 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1046 "RRChangeOutputProperty error, %d\n", err);
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));
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);
1060 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1062 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1063 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
1065 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1066 "RRConfigureOutputProperty error, %d\n", err);
1069 for (j = 0; j < drmmode_prop->count_enums; j++)
1070 if (drmmode_prop->enums[j].value == p->value)
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);
1076 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1077 "RRChangeOutputProperty error, %d\n", err);
1082 if (intel_output->backlight_iface) {
1083 INT32 data, backlight_range[2];
1085 /* Set up the backlight property, which takes effect
1086 * immediately and accepts values only within the
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);
1093 backlight_range[0] = 0;
1094 backlight_range[1] = intel_output->backlight_max;
1095 err = RRConfigureOutputProperty(output->randr_output,
1098 2, backlight_range);
1100 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1101 "RRConfigureOutputProperty error, %d\n", err);
1103 err = RRConfigureOutputProperty(output->randr_output,
1104 backlight_deprecated_atom,
1106 2, backlight_range);
1108 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1109 "RRConfigureOutputProperty error, %d\n", err);
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,
1117 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1118 "RRChangeOutputProperty error, %d\n", err);
1120 err = RRChangeOutputProperty(output->randr_output, backlight_deprecated_atom,
1121 XA_INTEGER, 32, PropModeReplace, 1, &data,
1124 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1125 "RRChangeOutputProperty error, %d\n", err);
1131 intel_output_set_property(xf86OutputPtr output, Atom property,
1132 RRPropertyValuePtr value)
1134 struct intel_output *intel_output = output->driver_private;
1135 struct intel_mode *mode = intel_output->mode;
1138 if (property == backlight_atom || property == backlight_deprecated_atom) {
1141 if (value->type != XA_INTEGER || value->format != 32 ||
1147 val = *(INT32 *)value->data;
1148 if (val < 0 || val > intel_output->backlight_max)
1151 if (intel_output->dpms_mode == DPMSModeOn)
1152 intel_output_backlight_set(output, val);
1153 intel_output->backlight_active_level = val;
1157 for (i = 0; i < intel_output->num_props; i++) {
1158 struct intel_property *p = &intel_output->props[i];
1160 if (p->atoms[0] != property)
1163 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1166 if (value->type != XA_INTEGER || value->format != 32 ||
1169 val = *(uint32_t *)value->data;
1171 drmModeConnectorSetProperty(mode->fd, intel_output->output_id,
1172 p->mode_prop->prop_id, (uint64_t)val);
1174 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1179 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
1181 memcpy(&atom, value->data, 4);
1182 name = NameForAtom(atom);
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);
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.
1204 intel_output_get_property(xf86OutputPtr output, Atom property)
1206 struct intel_output *intel_output = output->driver_private;
1209 if (property == backlight_atom || property == backlight_deprecated_atom) {
1212 if (! intel_output->backlight_iface)
1215 val = intel_output_backlight_get(output);
1219 err = RRChangeOutputProperty(output->randr_output, property,
1220 XA_INTEGER, 32, PropModeReplace, 1, &val,
1223 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1224 "RRChangeOutputProperty error, %d\n", err);
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,
1240 .dpms = intel_output_dpms,
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,
1250 .detect = intel_output_detect,
1251 .mode_valid = intel_output_mode_valid,
1253 .get_modes = intel_output_get_modes,
1254 .destroy = intel_output_destroy
1257 static const int subpixel_conv_table[7] = {
1260 SubPixelHorizontalRGB,
1261 SubPixelHorizontalBGR,
1262 SubPixelVerticalRGB,
1263 SubPixelVerticalBGR,
1267 static const char *output_names[] = {
1286 intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, int num)
1288 xf86OutputPtr output;
1289 drmModeConnectorPtr koutput;
1290 drmModeEncoderPtr kencoder;
1291 struct intel_output *intel_output;
1292 const char *output_name;
1295 koutput = drmModeGetConnector(mode->fd,
1296 mode->mode_res->connectors[num]);
1300 kencoder = drmModeGetEncoder(mode->fd, koutput->encoders[0]);
1302 drmModeFreeConnector(koutput);
1306 if (koutput->connector_type < ARRAY_SIZE(output_names))
1307 output_name = output_names[koutput->connector_type];
1309 output_name = "UNKNOWN";
1310 snprintf(name, 32, "%s%d", output_name, koutput->connector_type_id);
1312 output = xf86OutputCreate (scrn, &intel_output_funcs, name);
1314 drmModeFreeEncoder(kencoder);
1315 drmModeFreeConnector(koutput);
1319 intel_output = calloc(sizeof(struct intel_output), 1);
1320 if (!intel_output) {
1321 xf86OutputDestroy(output);
1322 drmModeFreeConnector(koutput);
1323 drmModeFreeEncoder(kencoder);
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;
1332 output->mm_width = koutput->mmWidth;
1333 output->mm_height = koutput->mmHeight;
1335 output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1336 output->driver_private = intel_output;
1338 if (is_panel(koutput->connector_type))
1339 intel_output_backlight_init(output);
1341 output->possible_crtcs = kencoder->possible_crtcs;
1342 output->possible_clones = kencoder->possible_clones;
1343 output->interlaceAllowed = TRUE;
1345 intel_output->output = output;
1346 list_add(&intel_output->link, &mode->outputs);
1350 intel_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
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;
1359 int i, old_width, old_height, old_pitch;
1360 unsigned long pitch;
1363 if (scrn->virtualX == width && scrn->virtualY == height)
1366 intel_batch_submit(scrn);
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;
1374 intel->front_buffer = intel_allocate_framebuffer(scrn,
1379 if (!intel->front_buffer)
1382 ret = drmModeAddFB(mode->fd, width, height, scrn->depth,
1383 scrn->bitsPerPixel, pitch,
1384 intel->front_buffer->handle,
1389 intel->front_pitch = pitch;
1390 intel->front_tiling = tiling;
1392 scrn->virtualX = width;
1393 scrn->virtualY = height;
1395 for (i = 0; i < xf86_config->num_crtc; i++) {
1396 xf86CrtcPtr crtc = xf86_config->crtc[i];
1401 if (!intel_crtc_apply(crtc))
1405 intel_uxa_create_screen_resources(scrn->pScreen);
1408 drmModeRmFB(mode->fd, old_fb_id);
1410 drm_intel_bo_unreference(old_front);
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;
1429 intel_do_pageflip(intel_screen_private *intel,
1431 DRI2FrameEventPtr flip_info, int ref_crtc_hw_id)
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;
1442 * Create a new handle for the back buffer
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))
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.
1456 * Also, flips queued on disabled or incorrectly configured displays
1457 * may never complete; this is a configuration error.
1460 mode->fe_tv_sec = 0;
1461 mode->fe_tv_usec = 0;
1463 for (i = 0; i < config->num_crtc; i++) {
1464 if (!config->crtc[i]->enabled)
1467 mode->flip_info = flip_info;
1470 crtc = config->crtc[i]->driver_private;
1472 flip = calloc(1, sizeof(struct intel_pageflip));
1474 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1475 "flip queue: carrier alloc failed.\n");
1479 /* Only the reference crtc will finally deliver its page flip
1480 * completion event. All other crtc's events will be discarded.
1482 flip->dispatch_me = (intel_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id);
1485 if (drmModePageFlip(mode->fd,
1488 DRM_MODE_PAGE_FLIP_EVENT, flip)) {
1489 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1490 "flip queue failed: %s\n", strerror(errno));
1496 mode->old_fb_id = old_fb_id;
1500 drmModeRmFB(mode->fd, mode->fb_id);
1501 mode->fb_id = old_fb_id;
1504 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
1509 static const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = {
1510 intel_xf86crtc_resize
1514 intel_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
1515 unsigned int tv_usec, void *event)
1517 I830DRI2FrameEventHandler(frame, tv_sec, tv_usec, event);
1521 intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
1522 unsigned int tv_usec, void *event_data)
1524 struct intel_pageflip *flip = event_data;
1525 struct intel_mode *mode = flip->mode;
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;
1536 /* Last crtc completed flip? */
1538 if (mode->flip_count > 0)
1541 /* Release framebuffer */
1542 drmModeRmFB(mode->fd, mode->old_fb_id);
1544 if (mode->flip_info == NULL)
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);
1553 drm_wakeup_handler(pointer data, int err, pointer p)
1555 struct intel_mode *mode;
1558 if (data == NULL || err < 0)
1563 if (FD_ISSET(mode->fd, read_mask))
1564 drmHandleEvent(mode->fd, &mode->event_context);
1567 Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
1569 intel_screen_private *intel = intel_get_screen_private(scrn);
1570 struct drm_i915_getparam gp;
1571 struct intel_mode *mode;
1575 mode = calloc(1, sizeof *mode);
1581 list_init(&mode->crtcs);
1582 list_init(&mode->outputs);
1584 xf86CrtcConfigInit(scrn, &intel_xf86crtc_config_funcs);
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));
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);
1600 for (i = 0; i < mode->mode_res->count_connectors; i++)
1601 intel_output_init(scrn, mode, i);
1603 xf86InitialConfiguration(scrn, TRUE);
1606 gp.param = I915_PARAM_HAS_PAGEFLIPPING;
1607 gp.value = &has_flipping;
1608 (void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp,
1611 xf86DrvMsg(scrn->scrnIndex, X_INFO,
1612 "Kernel page flipping support detected, enabling\n");
1613 intel->use_pageflipping = TRUE;
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;
1620 intel->modes = mode;
1625 intel_mode_init(struct intel_screen_private *intel)
1627 if (intel->use_pageflipping) {
1628 struct intel_mode *mode = intel->modes;
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.
1634 mode->flip_count = 0;
1635 AddGeneralSocket(mode->fd);
1636 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1637 drm_wakeup_handler, mode);
1642 intel_mode_remove_fb(intel_screen_private *intel)
1644 struct intel_mode *mode = intel->modes;
1647 drmModeRmFB(mode->fd, mode->fb_id);
1653 intel_mode_fini(intel_screen_private *intel)
1655 struct intel_mode *mode = intel->modes;
1657 while(!list_is_empty(&mode->crtcs)) {
1658 xf86CrtcDestroy(list_first_entry(&mode->crtcs,
1663 while(!list_is_empty(&mode->outputs)) {
1664 xf86OutputDestroy(list_first_entry(&mode->outputs,
1665 struct intel_output,
1670 drmModeRmFB(mode->fd, mode->fb_id);
1672 /* mode->rotate_fb_id should have been destroyed already */
1675 intel->modes = NULL;
1678 /* for the mode overlay */
1680 intel_crtc_id(xf86CrtcPtr crtc)
1682 return crtc_id(crtc->driver_private);
1685 int intel_crtc_to_pipe(xf86CrtcPtr crtc)
1687 struct intel_crtc *intel_crtc = crtc->driver_private;
1688 return intel_crtc->pipe;