2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Author: Alan Hourihane <alanh@tungstengraphics.com>
27 * Author: Jakob Bornecrantz <wallbraker@gmail.com>
32 #include "xorg-server.h"
34 #include "xf86_OSproc.h"
36 #include "xf86PciInfo.h"
38 #include "mipointer.h"
40 #include <X11/extensions/randr.h>
45 #include "miscstruct.h"
46 #include "dixstruct.h"
48 #include <X11/extensions/Xv.h>
49 #ifndef XSERVER_LIBPCIACCESS
50 #error "libpciaccess needed"
53 #include <pciaccess.h>
55 #include "pipe/p_context.h"
56 #include "xorg_tracker.h"
57 #include "xorg_winsys.h"
59 static void AdjustFrame(int scrnIndex
, int x
, int y
, int flags
);
60 static Bool
CloseScreen(int scrnIndex
, ScreenPtr pScreen
);
61 static Bool
EnterVT(int scrnIndex
, int flags
);
62 static Bool
SaveHWState(ScrnInfoPtr pScrn
);
63 static Bool
RestoreHWState(ScrnInfoPtr pScrn
);
66 static ModeStatus
ValidMode(int scrnIndex
, DisplayModePtr mode
, Bool verbose
,
68 static void FreeScreen(int scrnIndex
, int flags
);
69 static void LeaveVT(int scrnIndex
, int flags
);
70 static Bool
SwitchMode(int scrnIndex
, DisplayModePtr mode
, int flags
);
71 static Bool
ScreenInit(int scrnIndex
, ScreenPtr pScreen
, int argc
,
73 static Bool
PreInit(ScrnInfoPtr pScrn
, int flags
);
80 static const OptionInfoRec Options
[] = {
81 {OPTION_SW_CURSOR
, "SWcursor", OPTV_BOOLEAN
, {0}, FALSE
},
82 {-1, NULL
, OPTV_NONE
, {0}, FALSE
}
86 * Exported Xorg driver functions to winsys
90 xorg_tracker_available_options(int chipid
, int busid
)
96 xorg_tracker_set_functions(ScrnInfoPtr scrn
)
98 scrn
->PreInit
= PreInit
;
99 scrn
->ScreenInit
= ScreenInit
;
100 scrn
->SwitchMode
= SwitchMode
;
101 scrn
->AdjustFrame
= AdjustFrame
;
102 scrn
->EnterVT
= EnterVT
;
103 scrn
->LeaveVT
= LeaveVT
;
104 scrn
->FreeScreen
= FreeScreen
;
105 scrn
->ValidMode
= ValidMode
;
109 * Static Xorg funtctions
113 GetRec(ScrnInfoPtr pScrn
)
115 if (pScrn
->driverPrivate
)
118 pScrn
->driverPrivate
= xnfcalloc(sizeof(modesettingRec
), 1);
124 FreeRec(ScrnInfoPtr pScrn
)
129 if (!pScrn
->driverPrivate
)
132 xfree(pScrn
->driverPrivate
);
134 pScrn
->driverPrivate
= NULL
;
138 ProbeDDC(ScrnInfoPtr pScrn
, int index
)
140 ConfiguredMonitor
= NULL
;
144 CreateFrontBuffer(ScrnInfoPtr pScrn
)
146 modesettingPtr ms
= modesettingPTR(pScrn
);
147 ScreenPtr pScreen
= pScrn
->pScreen
;
148 PixmapPtr rootPixmap
= pScreen
->GetScreenPixmap(pScreen
);
149 unsigned handle
, stride
;
152 xorg_exa_set_displayed_usage(rootPixmap
);
153 pScreen
->ModifyPixmapHeader(rootPixmap
,
154 pScrn
->virtualX
, pScrn
->virtualY
,
155 pScrn
->depth
, pScrn
->bitsPerPixel
,
156 pScrn
->displayWidth
* pScrn
->bitsPerPixel
/ 8,
160 handle
= xorg_exa_get_pixmap_handle(rootPixmap
, &stride
);
173 AdjustFrame(pScrn
->scrnIndex
, pScrn
->frameX0
, pScrn
->frameY0
, 0);
179 crtc_resize(ScrnInfoPtr pScrn
, int width
, int height
)
181 modesettingPtr ms
= modesettingPTR(pScrn
);
182 //ScreenPtr pScreen = pScrn->pScreen;
183 //PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
184 //Bool fbAccessDisabled;
187 if (width
== pScrn
->virtualX
&& height
== pScrn
->virtualY
)
190 ErrorF("RESIZING TO %dx%d\n", width
, height
);
192 pScrn
->virtualX
= width
;
193 pScrn
->virtualY
= height
;
195 /* HW dependent - FIXME */
196 pScrn
->displayWidth
= pScrn
->virtualX
;
198 drmModeRmFB(ms
->fd
, ms
->fb_id
);
200 /* now create new frontbuffer */
201 return CreateFrontBuffer(pScrn
);
204 static const xf86CrtcConfigFuncsRec crtc_config_funcs
= {
209 PreInit(ScrnInfoPtr pScrn
, int flags
)
211 xf86CrtcConfigPtr xf86_config
;
213 rgb defaultWeight
= { 0, 0, 0 };
217 int max_width
, max_height
;
219 if (pScrn
->numEntities
!= 1)
222 pEnt
= xf86GetEntityInfo(pScrn
->entityList
[0]);
224 if (flags
& PROBE_DETECT
) {
225 ProbeDDC(pScrn
, pEnt
->index
);
229 /* Allocate driverPrivate */
233 ms
= modesettingPTR(pScrn
);
234 ms
->SaveGeneration
= -1;
237 pScrn
->displayWidth
= 640; /* default it */
239 if (ms
->pEnt
->location
.type
!= BUS_PCI
)
242 ms
->PciInfo
= xf86GetPciInfoForEntity(ms
->pEnt
->index
);
244 /* Allocate an entity private if necessary */
245 if (xf86IsEntityShared(pScrn
->entityList
[0])) {
246 FatalError("Entity");
248 msEnt
= xf86GetEntityPrivate(pScrn
->entityList
[0],
249 modesettingEntityIndex
)->ptr
;
250 ms
->entityPrivate
= msEnt
;
255 ms
->entityPrivate
= NULL
;
257 if (xf86IsEntityShared(pScrn
->entityList
[0])) {
258 if (xf86IsPrimInitDone(pScrn
->entityList
[0])) {
261 xf86SetPrimInitDone(pScrn
->entityList
[0]);
266 sprintf(BusID
, "PCI:%d:%d:%d",
267 ((ms
->PciInfo
->domain
<< 8) | ms
->PciInfo
->bus
),
268 ms
->PciInfo
->dev
, ms
->PciInfo
->func
271 ms
->api
= drm_api_create();
272 ms
->fd
= drmOpen(NULL
, BusID
);
277 pScrn
->monitor
= pScrn
->confScreen
->monitor
;
278 pScrn
->progClock
= TRUE
;
283 PreferConvert24to32
| SupportConvert24to32
| Support32bppFb
))
286 switch (pScrn
->depth
) {
292 xf86DrvMsg(pScrn
->scrnIndex
, X_ERROR
,
293 "Given depth (%d) is not supported by the driver\n",
297 xf86PrintDepthBpp(pScrn
);
299 if (!xf86SetWeight(pScrn
, defaultWeight
, defaultWeight
))
301 if (!xf86SetDefaultVisual(pScrn
, -1))
304 /* Process the options */
305 xf86CollectOptions(pScrn
, NULL
);
306 if (!(ms
->Options
= xalloc(sizeof(Options
))))
308 memcpy(ms
->Options
, Options
, sizeof(Options
));
309 xf86ProcessOptions(pScrn
->scrnIndex
, pScrn
->options
, ms
->Options
);
311 /* Allocate an xf86CrtcConfig */
312 xf86CrtcConfigInit(pScrn
, &crtc_config_funcs
);
313 xf86_config
= XF86_CRTC_CONFIG_PTR(pScrn
);
317 xf86CrtcSetSizeRange(pScrn
, 320, 200, max_width
, max_height
);
319 if (xf86ReturnOptValBool(ms
->Options
, OPTION_SW_CURSOR
, FALSE
)) {
328 if (!xf86InitialConfiguration(pScrn
, TRUE
)) {
329 xf86DrvMsg(pScrn
->scrnIndex
, X_ERROR
, "No valid modes.\n");
330 RestoreHWState(pScrn
);
334 RestoreHWState(pScrn
);
337 * If the driver can do gamma correction, it should call xf86SetGamma() here.
340 Gamma zeros
= { 0.0, 0.0, 0.0 };
342 if (!xf86SetGamma(pScrn
, zeros
)) {
347 if (pScrn
->modes
== NULL
) {
348 xf86DrvMsg(pScrn
->scrnIndex
, X_ERROR
, "No modes.\n");
352 pScrn
->currentMode
= pScrn
->modes
;
354 /* Set display resolution */
355 xf86SetDpi(pScrn
, 0, 0);
357 /* Load the required sub modules */
358 if (!xf86LoadSubModule(pScrn
, "fb")) {
362 xf86LoadSubModule(pScrn
, "exa");
365 xf86LoadSubModule(pScrn
, "dri2");
372 SaveHWState(ScrnInfoPtr pScrn
)
374 /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/
380 RestoreHWState(ScrnInfoPtr pScrn
)
382 /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/
387 static void xorgBlockHandler(int i
, pointer blockData
, pointer pTimeout
,
390 ScreenPtr pScreen
= screenInfo
.screens
[i
];
391 modesettingPtr ms
= modesettingPTR(xf86Screens
[pScreen
->myNum
]);
393 pScreen
->BlockHandler
= ms
->blockHandler
;
394 pScreen
->BlockHandler(i
, blockData
, pTimeout
, pReadmask
);
395 pScreen
->BlockHandler
= xorgBlockHandler
;
397 ms
->ctx
->flush(ms
->ctx
, PIPE_FLUSH_RENDER_CACHE
, NULL
);
399 #ifdef DRM_MODE_FEATURE_DIRTYFB
401 RegionPtr dirty
= DamageRegion(ms
->damage
);
402 unsigned num_cliprects
= REGION_NUM_RECTS(dirty
);
405 drmModeClip
*clip
= alloca(num_cliprects
* sizeof(drmModeClip
));
406 BoxPtr rect
= REGION_RECTS(dirty
);
409 for (i
= 0; i
< num_cliprects
; i
++, rect
++) {
410 clip
[i
].x
= rect
->x1
;
411 clip
[i
].y
= rect
->y1
;
412 clip
[i
].width
= rect
->x2
- rect
->x1
;
413 clip
[i
].height
= rect
->y2
- rect
->y1
;
416 /* TODO query connector property to see if this is needed */
417 drmModeDirtyFB(ms
->fd
, ms
->fb_id
, clip
, num_cliprects
);
419 DamageEmpty(ms
->damage
);
426 CreateScreenResources(ScreenPtr pScreen
)
428 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
429 modesettingPtr ms
= modesettingPTR(pScrn
);
430 PixmapPtr rootPixmap
;
432 unsigned handle
, stride
;
436 pScreen
->CreateScreenResources
= ms
->createScreenResources
;
437 ret
= pScreen
->CreateScreenResources(pScreen
);
438 pScreen
->CreateScreenResources
= CreateScreenResources
;
440 rootPixmap
= pScreen
->GetScreenPixmap(pScreen
);
442 xorg_exa_set_displayed_usage(rootPixmap
);
443 xorg_exa_set_shared_usage(rootPixmap
);
444 if (!pScreen
->ModifyPixmapHeader(rootPixmap
, -1, -1, -1, -1, -1, NULL
))
445 FatalError("Couldn't adjust screen pixmap\n");
449 handle
= xorg_exa_get_pixmap_handle(rootPixmap
, &stride
);
460 AdjustFrame(pScrn
->scrnIndex
, pScrn
->frameX0
, pScrn
->frameY0
, 0);
462 #ifdef DRM_MODE_FEATURE_DIRTYFB
463 ms
->damage
= DamageCreate(NULL
, NULL
, DamageReportNone
, TRUE
,
464 pScreen
, rootPixmap
);
467 DamageRegister(&rootPixmap
->drawable
, ms
->damage
);
469 xf86DrvMsg(pScrn
->scrnIndex
, X_INFO
, "Damage tracking initialized\n");
471 xf86DrvMsg(pScrn
->scrnIndex
, X_ERROR
,
472 "Failed to create screen damage record\n");
481 ScreenInit(int scrnIndex
, ScreenPtr pScreen
, int argc
, char **argv
)
483 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
484 modesettingPtr ms
= modesettingPTR(pScrn
);
487 /* deal with server regeneration */
492 sprintf(BusID
, "PCI:%d:%d:%d",
493 ((ms
->PciInfo
->domain
<< 8) | ms
->PciInfo
->bus
),
494 ms
->PciInfo
->dev
, ms
->PciInfo
->func
497 ms
->fd
= drmOpen(NULL
, BusID
);
504 ms
->screen
= ms
->api
->create_screen(ms
->api
, ms
->fd
, NULL
);
507 FatalError("Could not init pipe_screen\n");
512 pScrn
->pScreen
= pScreen
;
514 /* HW dependent - FIXME */
515 pScrn
->displayWidth
= pScrn
->virtualX
;
517 miClearVisualTypes();
519 if (!miSetVisualTypes(pScrn
->depth
,
520 miGetDefaultVisualMask(pScrn
->depth
),
521 pScrn
->rgbBits
, pScrn
->defaultVisual
))
524 if (!miSetPixmapDepths())
527 pScrn
->memPhysBase
= 0;
530 if (!fbScreenInit(pScreen
, NULL
,
531 pScrn
->virtualX
, pScrn
->virtualY
,
532 pScrn
->xDpi
, pScrn
->yDpi
,
533 pScrn
->displayWidth
, pScrn
->bitsPerPixel
))
536 if (pScrn
->bitsPerPixel
> 8) {
537 /* Fixup RGB ordering */
538 visual
= pScreen
->visuals
+ pScreen
->numVisuals
;
539 while (--visual
>= pScreen
->visuals
) {
540 if ((visual
->class | DynamicClass
) == DirectColor
) {
541 visual
->offsetRed
= pScrn
->offset
.red
;
542 visual
->offsetGreen
= pScrn
->offset
.green
;
543 visual
->offsetBlue
= pScrn
->offset
.blue
;
544 visual
->redMask
= pScrn
->mask
.red
;
545 visual
->greenMask
= pScrn
->mask
.green
;
546 visual
->blueMask
= pScrn
->mask
.blue
;
551 fbPictureInit(pScreen
, NULL
, 0);
553 ms
->blockHandler
= pScreen
->BlockHandler
;
554 pScreen
->BlockHandler
= xorgBlockHandler
;
555 ms
->createScreenResources
= pScreen
->CreateScreenResources
;
556 pScreen
->CreateScreenResources
= CreateScreenResources
;
558 xf86SetBlackWhitePixels(pScreen
);
560 ms
->exa
= xorg_exa_init(pScrn
);
561 ms
->debug_fallback
= debug_get_bool_option("XORG_DEBUG_FALLBACK", TRUE
);
563 xorg_init_video(pScreen
);
565 miInitializeBackingStore(pScreen
);
566 xf86SetBackingStore(pScreen
);
567 xf86SetSilkenMouse(pScreen
);
568 miDCInitialize(pScreen
, xf86GetPointerScreenFuncs());
570 /* Need to extend HWcursor support to handle mask interleave */
572 xf86_cursors_init(pScreen
, 64, 64,
573 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64
|
574 HARDWARE_CURSOR_ARGB
);
576 /* Must force it before EnterVT, so we are in control of VT and
577 * later memory should be bound when allocating, e.g rotate_mem */
578 pScrn
->vtSema
= TRUE
;
580 pScreen
->SaveScreen
= xf86SaveScreen
;
581 ms
->CloseScreen
= pScreen
->CloseScreen
;
582 pScreen
->CloseScreen
= CloseScreen
;
584 if (!xf86CrtcScreenInit(pScreen
))
587 if (!miCreateDefColormap(pScreen
))
590 xf86DPMSInit(pScreen
, xf86DPMSSet
, 0);
592 if (serverGeneration
== 1)
593 xf86ShowUnusedOptions(pScrn
->scrnIndex
, pScrn
->options
);
597 driScreenInit(pScreen
);
601 return EnterVT(scrnIndex
, 1);
605 AdjustFrame(int scrnIndex
, int x
, int y
, int flags
)
607 ScrnInfoPtr pScrn
= xf86Screens
[scrnIndex
];
608 xf86CrtcConfigPtr config
= XF86_CRTC_CONFIG_PTR(pScrn
);
609 xf86OutputPtr output
= config
->output
[config
->compat_output
];
610 xf86CrtcPtr crtc
= output
->crtc
;
612 if (crtc
&& crtc
->enabled
) {
613 crtc
->funcs
->mode_set(crtc
, pScrn
->currentMode
, pScrn
->currentMode
, x
,
615 crtc
->x
= output
->initial_x
+ x
;
616 crtc
->y
= output
->initial_y
+ y
;
621 FreeScreen(int scrnIndex
, int flags
)
623 FreeRec(xf86Screens
[scrnIndex
]);
627 LeaveVT(int scrnIndex
, int flags
)
629 ScrnInfoPtr pScrn
= xf86Screens
[scrnIndex
];
630 modesettingPtr ms
= modesettingPTR(pScrn
);
631 xf86CrtcConfigPtr config
= XF86_CRTC_CONFIG_PTR(pScrn
);
634 for (o
= 0; o
< config
->num_crtc
; o
++) {
635 xf86CrtcPtr crtc
= config
->crtc
[o
];
637 crtc_cursor_destroy(crtc
);
639 if (crtc
->rotatedPixmap
|| crtc
->rotatedData
) {
640 crtc
->funcs
->shadow_destroy(crtc
, crtc
->rotatedPixmap
,
642 crtc
->rotatedPixmap
= NULL
;
643 crtc
->rotatedData
= NULL
;
647 drmModeRmFB(ms
->fd
, ms
->fb_id
);
649 RestoreHWState(pScrn
);
651 if (drmDropMaster(ms
->fd
))
652 xf86DrvMsg(pScrn
->scrnIndex
, X_WARNING
,
653 "drmDropMaster failed: %s\n", strerror(errno
));
655 pScrn
->vtSema
= FALSE
;
659 * This gets called when gaining control of the VT, and from ScreenInit().
662 EnterVT(int scrnIndex
, int flags
)
664 ScrnInfoPtr pScrn
= xf86Screens
[scrnIndex
];
665 modesettingPtr ms
= modesettingPTR(pScrn
);
667 if (drmSetMaster(ms
->fd
)) {
668 if (errno
== EINVAL
) {
669 xf86DrvMsg(pScrn
->scrnIndex
, X_WARNING
,
670 "drmSetMaster failed: 2.6.29 or newer kernel required for "
671 "multi-server DRI\n");
673 xf86DrvMsg(pScrn
->scrnIndex
, X_WARNING
,
674 "drmSetMaster failed: %s\n", strerror(errno
));
679 * Only save state once per server generation since that's what most
680 * drivers do. Could change this to save state at each VT enter.
682 if (ms
->SaveGeneration
!= serverGeneration
) {
683 ms
->SaveGeneration
= serverGeneration
;
687 if (!flags
) /* signals startup as we'll do this in CreateScreenResources */
688 CreateFrontBuffer(pScrn
);
690 if (!xf86SetDesiredModes(pScrn
))
697 SwitchMode(int scrnIndex
, DisplayModePtr mode
, int flags
)
699 ScrnInfoPtr pScrn
= xf86Screens
[scrnIndex
];
701 return xf86SetSingleMode(pScrn
, mode
, RR_Rotate_0
);
705 CloseScreen(int scrnIndex
, ScreenPtr pScreen
)
707 ScrnInfoPtr pScrn
= xf86Screens
[scrnIndex
];
708 modesettingPtr ms
= modesettingPTR(pScrn
);
711 LeaveVT(scrnIndex
, 0);
714 driCloseScreen(pScreen
);
717 pScreen
->BlockHandler
= ms
->blockHandler
;
718 pScreen
->CreateScreenResources
= ms
->createScreenResources
;
720 #ifdef DRM_MODE_FEATURE_DIRTYFB
722 DamageUnregister(&pScreen
->GetScreenPixmap(pScreen
)->drawable
, ms
->damage
);
723 DamageDestroy(ms
->damage
);
729 xorg_exa_close(pScrn
);
731 if (ms
->api
->destroy
)
732 ms
->api
->destroy(ms
->api
);
738 pScrn
->vtSema
= FALSE
;
739 pScreen
->CloseScreen
= ms
->CloseScreen
;
740 return (*pScreen
->CloseScreen
) (scrnIndex
, pScreen
);
744 ValidMode(int scrnIndex
, DisplayModePtr mode
, Bool verbose
, int flags
)
749 /* vim: set sw=4 ts=8 sts=4: */