cg6_driver.c revision 5eefee25
1/*
2 * GX and Turbo GX framebuffer driver.
3 *
4 * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * JAKUB JELINEK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/suncg6/cg6_driver.c,v 1.7 2002/12/06 16:44:38 tsi Exp $ */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <string.h>
30
31#include "xf86.h"
32#include "xf86_OSproc.h"
33#include "xf86Version.h"
34#include "mipointer.h"
35#include "mibstore.h"
36#include "micmap.h"
37
38#include "fb.h"
39#include "xf86cmap.h"
40#include "cg6.h"
41
42static const OptionInfoRec * CG6AvailableOptions(int chipid, int busid);
43static void	CG6Identify(int flags);
44static Bool	CG6Probe(DriverPtr drv, int flags);
45static Bool	CG6PreInit(ScrnInfoPtr pScrn, int flags);
46static Bool	CG6ScreenInit(int Index, ScreenPtr pScreen, int argc,
47			      char **argv);
48static Bool	CG6EnterVT(int scrnIndex, int flags);
49static void	CG6LeaveVT(int scrnIndex, int flags);
50static Bool	CG6CloseScreen(int scrnIndex, ScreenPtr pScreen);
51static Bool	CG6SaveScreen(ScreenPtr pScreen, int mode);
52
53/* Required if the driver supports mode switching */
54static Bool	CG6SwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
55/* Required if the driver supports moving the viewport */
56static void	CG6AdjustFrame(int scrnIndex, int x, int y, int flags);
57
58/* Optional functions */
59static void	CG6FreeScreen(int scrnIndex, int flags);
60static ModeStatus CG6ValidMode(int scrnIndex, DisplayModePtr mode,
61			       Bool verbose, int flags);
62
63void CG6Sync(ScrnInfoPtr pScrn);
64
65#define CG6_VERSION 4000
66#define CG6_NAME "SUNCG6"
67#define CG6_DRIVER_NAME "suncg6"
68#define CG6_MAJOR_VERSION 1
69#define CG6_MINOR_VERSION 1
70#define CG6_PATCHLEVEL 0
71
72/*
73 * This contains the functions needed by the server after loading the driver
74 * module.  It must be supplied, and gets passed back by the SetupProc
75 * function in the dynamic case.  In the static case, a reference to this
76 * is compiled in, and this requires that the name of this DriverRec be
77 * an upper-case version of the driver name.
78 */
79
80_X_EXPORT DriverRec SUNCG6 = {
81    CG6_VERSION,
82    CG6_DRIVER_NAME,
83    CG6Identify,
84    CG6Probe,
85    CG6AvailableOptions,
86    NULL,
87    0
88};
89
90typedef enum {
91    OPTION_SW_CURSOR,
92    OPTION_HW_CURSOR,
93    OPTION_NOACCEL
94} CG6Opts;
95
96static const OptionInfoRec CG6Options[] = {
97    { OPTION_SW_CURSOR,		"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
98    { OPTION_HW_CURSOR,		"HWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
99    { OPTION_NOACCEL,		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
100    { -1,			NULL,		OPTV_NONE,	{0}, FALSE }
101};
102
103#ifdef XFree86LOADER
104
105static MODULESETUPPROTO(cg6Setup);
106
107static XF86ModuleVersionInfo suncg6VersRec =
108{
109	"suncg6",
110	MODULEVENDORSTRING,
111	MODINFOSTRING1,
112	MODINFOSTRING2,
113	XORG_VERSION_CURRENT,
114	CG6_MAJOR_VERSION, CG6_MINOR_VERSION, CG6_PATCHLEVEL,
115	ABI_CLASS_VIDEODRV,
116	ABI_VIDEODRV_VERSION,
117	MOD_CLASS_VIDEODRV,
118	{0,0,0,0}
119};
120
121_X_EXPORT XF86ModuleData suncg6ModuleData = { &suncg6VersRec, cg6Setup, NULL };
122
123pointer
124cg6Setup(pointer module, pointer opts, int *errmaj, int *errmin)
125{
126    static Bool setupDone = FALSE;
127
128    if (!setupDone) {
129	setupDone = TRUE;
130	xf86AddDriver(&SUNCG6, module, 0);
131
132	/*
133	 * Modules that this driver always requires can be loaded here
134	 * by calling LoadSubModule().
135	 */
136
137	/*
138	 * The return value must be non-NULL on success even though there
139	 * is no TearDownProc.
140	 */
141	return (pointer)TRUE;
142    } else {
143	if (errmaj) *errmaj = LDR_ONCEONLY;
144	return NULL;
145    }
146}
147
148#endif /* XFree86LOADER */
149
150static Bool
151CG6GetRec(ScrnInfoPtr pScrn)
152{
153    /*
154     * Allocate an Cg6Rec, and hook it into pScrn->driverPrivate.
155     * pScrn->driverPrivate is initialised to NULL, so we can check if
156     * the allocation has already been done.
157     */
158    if (pScrn->driverPrivate != NULL)
159	return TRUE;
160
161    pScrn->driverPrivate = xnfcalloc(sizeof(Cg6Rec), 1);
162    return TRUE;
163}
164
165static void
166CG6FreeRec(ScrnInfoPtr pScrn)
167{
168    Cg6Ptr pCg6;
169
170    if (pScrn->driverPrivate == NULL)
171	return;
172
173    pCg6 = GET_CG6_FROM_SCRN(pScrn);
174
175    xfree(pScrn->driverPrivate);
176    pScrn->driverPrivate = NULL;
177
178    return;
179}
180
181static const OptionInfoRec *
182CG6AvailableOptions(int chipid, int busid)
183{
184    return CG6Options;
185}
186
187/* Mandatory */
188static void
189CG6Identify(int flags)
190{
191    xf86Msg(X_INFO, "%s: driver for CGsix (GX and Turbo GX)\n", CG6_NAME);
192}
193
194
195/* Mandatory */
196static Bool
197CG6Probe(DriverPtr drv, int flags)
198{
199    int i;
200    GDevPtr *devSections;
201    int *usedChips;
202    int numDevSections;
203    int numUsed;
204    Bool foundScreen = FALSE;
205    EntityInfoPtr pEnt;
206
207    /*
208     * The aim here is to find all cards that this driver can handle,
209     * and for the ones not already claimed by another driver, claim the
210     * slot, and allocate a ScrnInfoRec.
211     *
212     * This should be a minimal probe, and it should under no circumstances
213     * change the state of the hardware.  Because a device is found, don't
214     * assume that it will be used.  Don't do any initialisations other than
215     * the required ScrnInfoRec initialisations.  Don't allocate any new
216     * data structures.
217     */
218
219    /*
220     * Next we check, if there has been a chipset override in the config file.
221     * For this we must find out if there is an active device section which
222     * is relevant, i.e., which has no driver specified or has THIS driver
223     * specified.
224     */
225
226    if ((numDevSections = xf86MatchDevice(CG6_DRIVER_NAME,
227					  &devSections)) <= 0) {
228	/*
229	 * There's no matching device section in the config file, so quit
230	 * now.
231	 */
232	return FALSE;
233    }
234
235    /*
236     * We need to probe the hardware first.  We then need to see how this
237     * fits in with what is given in the config file, and allow the config
238     * file info to override any contradictions.
239     */
240
241    numUsed = xf86MatchSbusInstances(CG6_NAME, SBUS_DEVICE_CG6,
242		   devSections, numDevSections,
243		   drv, &usedChips);
244
245    xfree(devSections);
246    if (numUsed <= 0)
247	return FALSE;
248
249    if (flags & PROBE_DETECT)
250	foundScreen = TRUE;
251    else for (i = 0; i < numUsed; i++) {
252	pEnt = xf86GetEntityInfo(usedChips[i]);
253
254	/*
255	 * Check that nothing else has claimed the slots.
256	 */
257	if(pEnt->active) {
258	    ScrnInfoPtr pScrn;
259
260	    /* Allocate a ScrnInfoRec and claim the slot */
261	    pScrn = xf86AllocateScreen(drv, 0);
262
263	    /* Fill in what we can of the ScrnInfoRec */
264	    pScrn->driverVersion = CG6_VERSION;
265	    pScrn->driverName	 = CG6_DRIVER_NAME;
266	    pScrn->name		 = CG6_NAME;
267	    pScrn->Probe	 = CG6Probe;
268	    pScrn->PreInit	 = CG6PreInit;
269	    pScrn->ScreenInit	 = CG6ScreenInit;
270  	    pScrn->SwitchMode	 = CG6SwitchMode;
271  	    pScrn->AdjustFrame	 = CG6AdjustFrame;
272	    pScrn->EnterVT	 = CG6EnterVT;
273	    pScrn->LeaveVT	 = CG6LeaveVT;
274	    pScrn->FreeScreen	 = CG6FreeScreen;
275	    pScrn->ValidMode	 = CG6ValidMode;
276	    xf86AddEntityToScreen(pScrn, pEnt->index);
277	    foundScreen = TRUE;
278	}
279	xfree(pEnt);
280    }
281    xfree(usedChips);
282    return foundScreen;
283}
284
285/* Mandatory */
286static Bool
287CG6PreInit(ScrnInfoPtr pScrn, int flags)
288{
289    Cg6Ptr pCg6;
290    sbusDevicePtr psdp;
291    MessageType from;
292    int i;
293
294    if (flags & PROBE_DETECT) return FALSE;
295
296    /*
297     * Note: This function is only called once at server startup, and
298     * not at the start of each server generation.  This means that
299     * only things that are persistent across server generations can
300     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
301     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
302     * are too, and should be used for data that must persist across
303     * server generations.
304     *
305     * Per-generation data should be allocated with
306     * AllocateScreenPrivateIndex() from the ScreenInit() function.
307     */
308
309    /* Allocate the Cg6Rec driverPrivate */
310    if (!CG6GetRec(pScrn)) {
311	return FALSE;
312    }
313    pCg6 = GET_CG6_FROM_SCRN(pScrn);
314
315    /* Set pScrn->monitor */
316    pScrn->monitor = pScrn->confScreen->monitor;
317
318    /* This driver doesn't expect more than one entity per screen */
319    if (pScrn->numEntities > 1)
320	return FALSE;
321    /* This is the general case */
322    for (i = 0; i < pScrn->numEntities; i++) {
323	EntityInfoPtr pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
324
325	/* CG6 is purely SBUS */
326	if (pEnt->location.type == BUS_SBUS) {
327	    psdp = xf86GetSbusInfoForEntity(pEnt->index);
328	    pCg6->psdp = psdp;
329	} else
330	    return FALSE;
331    }
332
333    /*********************
334    deal with depth
335    *********************/
336
337    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, NoDepth24Support)) {
338	return FALSE;
339    } else {
340	/* Check that the returned depth is one we support */
341	switch (pScrn->depth) {
342	case 8:
343	    /* OK */
344	    break;
345	default:
346	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
347		       "Given depth (%d) is not supported by this driver\n",
348		       pScrn->depth);
349	    return FALSE;
350	}
351    }
352
353    /* Collect all of the relevant option flags (fill in pScrn->options) */
354    xf86CollectOptions(pScrn, NULL);
355    /* Process the options */
356    if (!(pCg6->Options = xalloc(sizeof(CG6Options))))
357	return FALSE;
358    memcpy(pCg6->Options, CG6Options, sizeof(CG6Options));
359    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pCg6->Options);
360
361    if (!xf86SetDefaultVisual(pScrn, -1))
362	return FALSE;
363
364    /*
365     * The new cmap code requires this to be initialised.
366     */
367
368    {
369	Gamma zeros = {0.0, 0.0, 0.0};
370
371	if (!xf86SetGamma(pScrn, zeros)) {
372	    return FALSE;
373	}
374    }
375
376    /* Set the bits per RGB for 8bpp mode */
377    from = X_DEFAULT;
378
379    /* determine whether we use hardware or software cursor */
380
381    pCg6->HWCursor = TRUE;
382    if (xf86GetOptValBool(pCg6->Options, OPTION_HW_CURSOR, &pCg6->HWCursor))
383	from = X_CONFIG;
384    if (xf86ReturnOptValBool(pCg6->Options, OPTION_SW_CURSOR, FALSE)) {
385	from = X_CONFIG;
386	pCg6->HWCursor = FALSE;
387    }
388
389    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
390		pCg6->HWCursor ? "HW" : "SW");
391
392    if (xf86ReturnOptValBool(pCg6->Options, OPTION_NOACCEL, FALSE)) {
393	pCg6->NoAccel = TRUE;
394	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
395    }
396
397    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
398	CG6FreeRec(pScrn);
399	return FALSE;
400    }
401
402    if (pCg6->HWCursor && xf86LoadSubModule(pScrn, "ramdac") == NULL) {
403	CG6FreeRec(pScrn);
404	return FALSE;
405    }
406
407    /*********************
408    set up clock and mode stuff
409    *********************/
410
411    pScrn->progClock = TRUE;
412
413    if(pScrn->display->virtualX || pScrn->display->virtualY) {
414	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
415		   "CG6 does not support a virtual desktop\n");
416	pScrn->display->virtualX = 0;
417	pScrn->display->virtualY = 0;
418    }
419
420    xf86SbusUseBuiltinMode(pScrn, pCg6->psdp);
421    pScrn->currentMode = pScrn->modes;
422    pScrn->displayWidth = pScrn->virtualX;
423
424    /* Set display resolution */
425    xf86SetDpi(pScrn, 0, 0);
426
427    return TRUE;
428}
429
430/* Mandatory */
431
432/* This gets called at the start of each server generation */
433
434static Bool
435CG6ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
436{
437    ScrnInfoPtr pScrn;
438    Cg6Ptr pCg6;
439    int ret;
440
441    /*
442     * First get the ScrnInfoRec
443     */
444    pScrn = xf86Screens[pScreen->myNum];
445
446    pCg6 = GET_CG6_FROM_SCRN(pScrn);
447
448    /* Map the CG6 memory */
449    pCg6->fbc =
450	xf86MapSbusMem (pCg6->psdp, CG6_FBC_VOFF,
451			CG6_RAM_VOFF - CG6_FBC_VOFF +
452			(pCg6->psdp->width * pCg6->psdp->height));
453
454    if (! pCg6->fbc)
455	return FALSE;
456
457    pCg6->fb = (unsigned char *)pCg6->fbc + CG6_RAM_VOFF - CG6_FBC_VOFF;
458    pCg6->thc = (Cg6ThcPtr)((char *)pCg6->fbc + CG6_THC_VOFF - CG6_FBC_VOFF);
459
460    /* Darken the screen for aesthetic reasons and set the viewport */
461    CG6SaveScreen(pScreen, SCREEN_SAVER_ON);
462
463    /*
464     * The next step is to setup the screen's visuals, and initialise the
465     * framebuffer code.  In cases where the framebuffer's default
466     * choices for things like visual layouts and bits per RGB are OK,
467     * this may be as simple as calling the framebuffer's ScreenInit()
468     * function.  If not, the visuals will need to be setup before calling
469     * a fb ScreenInit() function and fixed up after.
470     */
471
472    /*
473     * Reset visual list.
474     */
475    miClearVisualTypes();
476
477    /* Set the bits per RGB for 8bpp mode */
478    pScrn->rgbBits = 8;
479
480    /* Setup the visuals we support. */
481
482    if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
483			  pScrn->rgbBits, pScrn->defaultVisual))
484	return FALSE;
485
486    miSetPixmapDepths ();
487
488    /*
489     * Call the framebuffer layer's ScreenInit function, and fill in other
490     * pScreen fields.
491     */
492
493    ret = fbScreenInit(pScreen, pCg6->fb, pScrn->virtualX,
494		       pScrn->virtualY, pScrn->xDpi, pScrn->yDpi,
495		       pScrn->virtualX, 8);
496    if (!ret)
497	return FALSE;
498
499#ifdef RENDER
500    fbPictureInit (pScreen, 0, 0);
501#endif
502
503    miInitializeBackingStore(pScreen);
504    xf86SetBackingStore(pScreen);
505    xf86SetSilkenMouse(pScreen);
506
507    xf86SetBlackWhitePixels(pScreen);
508
509#if 0
510    if (!pCg6->NoAccel) {
511	extern Bool CG6AccelInit(ScreenPtr pScreen, Cg6Ptr pCg6);
512
513	if (!CG6AccelInit(pScreen, pCg6))
514	    return FALSE;
515	xf86Msg(X_INFO, "%s: Using acceleration\n", pCg6->psdp->device);
516    }
517#endif
518
519    /* Initialise cursor functions */
520    miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
521
522    /* Initialize HW cursor layer.
523       Must follow software cursor initialization*/
524    if (pCg6->HWCursor) {
525	extern Bool CG6HWCursorInit(ScreenPtr pScreen);
526
527	if(!CG6HWCursorInit(pScreen)) {
528	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
529		       "Hardware cursor initialization failed\n");
530	    return(FALSE);
531	}
532	xf86SbusHideOsHwCursor(pCg6->psdp);
533    }
534
535    /* Initialise default colourmap */
536    if (!miCreateDefColormap(pScreen))
537	return FALSE;
538
539    if(!xf86SbusHandleColormaps(pScreen, pCg6->psdp))
540	return FALSE;
541
542    pCg6->CloseScreen = pScreen->CloseScreen;
543    pScreen->CloseScreen = CG6CloseScreen;
544    pScreen->SaveScreen = CG6SaveScreen;
545
546    /* Report any unused options (only for the first generation) */
547    if (serverGeneration == 1) {
548	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
549    }
550
551    /* unblank the screen */
552    CG6SaveScreen(pScreen, SCREEN_SAVER_OFF);
553
554    /* Done */
555    return TRUE;
556}
557
558
559/* Usually mandatory */
560static Bool
561CG6SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
562{
563    return TRUE;
564}
565
566
567/*
568 * This function is used to initialize the Start Address - the first
569 * displayed location in the video memory.
570 */
571/* Usually mandatory */
572static void
573CG6AdjustFrame(int scrnIndex, int x, int y, int flags)
574{
575    /* we don't support virtual desktops */
576    return;
577}
578
579/*
580 * This is called when VT switching back to the X server.  Its job is
581 * to reinitialise the video mode.
582 */
583
584/* Mandatory */
585static Bool
586CG6EnterVT(int scrnIndex, int flags)
587{
588    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
589    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
590
591    if (pCg6->HWCursor) {
592	xf86SbusHideOsHwCursor (pCg6->psdp);
593	pCg6->CursorFg = 0;
594	pCg6->CursorBg = 0;
595    }
596    return TRUE;
597}
598
599
600/*
601 * This is called when VT switching away from the X server.
602 */
603
604/* Mandatory */
605static void
606CG6LeaveVT(int scrnIndex, int flags)
607{
608    return;
609}
610
611
612/*
613 * This is called at the end of each server generation.  It restores the
614 * original (text) mode.  It should really also unmap the video memory too.
615 */
616
617/* Mandatory */
618static Bool
619CG6CloseScreen(int scrnIndex, ScreenPtr pScreen)
620{
621    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
622    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
623
624    pScrn->vtSema = FALSE;
625
626    xf86UnmapSbusMem(pCg6->psdp, pCg6->fbc,
627		     CG6_RAM_VOFF - CG6_FBC_VOFF +
628		     (pCg6->psdp->width * pCg6->psdp->height));
629
630    if (pCg6->HWCursor)
631    	xf86SbusHideOsHwCursor(pCg6->psdp);
632
633    pScreen->CloseScreen = pCg6->CloseScreen;
634    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
635    return FALSE;
636}
637
638
639/* Free up any per-generation data structures */
640
641/* Optional */
642static void
643CG6FreeScreen(int scrnIndex, int flags)
644{
645    CG6FreeRec(xf86Screens[scrnIndex]);
646}
647
648
649/* Checks if a mode is suitable for the selected chipset. */
650
651/* Optional */
652static ModeStatus
653CG6ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
654{
655    if (mode->Flags & V_INTERLACE)
656	return(MODE_BAD);
657
658    return(MODE_OK);
659}
660
661/* Do screen blanking */
662
663/* Mandatory */
664static Bool
665CG6SaveScreen(ScreenPtr pScreen, int mode)
666{
667    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
668    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
669    unsigned int tmp = pCg6->thc->thc_misc;
670
671    switch(mode)
672    {
673    case SCREEN_SAVER_ON:
674    case SCREEN_SAVER_CYCLE:
675       tmp &= ~CG6_THC_MISC_SYNC_ENAB;
676       break;
677    case SCREEN_SAVER_OFF:
678    case SCREEN_SAVER_FORCER:
679       tmp |= CG6_THC_MISC_SYNC_ENAB;
680       break;
681    default:
682       return FALSE;
683    }
684
685    pCg6->thc->thc_misc = tmp;
686    return TRUE;
687}
688
689/*
690 * This is the implementation of the Sync() function.
691 */
692void
693CG6Sync(ScrnInfoPtr pScrn)
694{
695    return;
696}
697