summaryrefslogtreecommitdiff
path: root/src/cir_driver.c
blob: 1942b151eabaa5fff135718714b0e0444ef8e7d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
/*
 * Driver for CL-GD5480.
 * Itai Nahshon.
 *
 * Support for the CL-GD7548: David Monniaux
 *
 * This is mainly a cut & paste from the MGA driver.
 * Original autors and contributors list include:
 *	Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel,
 *	David Dawes, Andrew E. Mileski, Leonard N. Zubkoff,
 *	Guy DESBIEF
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/cir_driver.c,v 1.67 2001/05/15 10:19:37 eich Exp $ */

/* All drivers should typically include these */
#include "xf86.h"
#include "xf86_OSproc.h"

#include "xf86Resources.h"

/* All drivers need this */

/* Drivers for PCI hardware need this */
#include "xf86PciInfo.h"

/* Drivers that need to access the PCI config space directly need this */
#include "xf86Pci.h"

#include "cir.h"
#include "alp.h"
#include "lg.h"

#include "vbe.h"

/*
 * Forward definitions for the functions that make up the driver.
 */

/* Mandatory functions */

static const OptionInfoRec *	CIRAvailableOptions(int chipid, int busid);
static void	CIRIdentify(int flags);
static Bool	CIRProbe(DriverPtr drv, int flags);

static Bool lg_loaded = FALSE;
static Bool alp_loaded = FALSE;

#define CIR_VERSION 4000
#define CIR_NAME "CIRRUS"
#define CIR_DRIVER_NAME "cirrus"
#define CIR_MAJOR_VERSION PACKAGE_VERSION_MAJOR
#define CIR_MINOR_VERSION PACKAGE_VERSION_MINOR
#define CIR_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL

/*
 * This contains the functions needed by the server after loading the
 * driver module.  It must be supplied, and gets added to the driver list by
 * the Module Setup function in the dynamic case.  In the static case a
 * reference to this is compiled in, and this requires that the name of
 * this DriverRec be an upper-case version of the driver name.
 */

_X_EXPORT DriverRec CIRRUS = {
	CIR_VERSION,
	CIR_DRIVER_NAME,
	CIRIdentify,
	CIRProbe,
	CIRAvailableOptions,
	NULL,
	0
};

/* Supported chipsets */
SymTabRec CIRChipsets[] = {
	{ PCI_CHIP_GD5430,		"CLGD5430" },
	{ PCI_CHIP_GD5434_4,	"CLGD5434-4" },
	{ PCI_CHIP_GD5434_8,	"CLGD5434-8" },
	{ PCI_CHIP_GD5436,		"CLGD5436" },
/*  { PCI_CHIP_GD5440,		"CLGD5440" }, */
	{ PCI_CHIP_GD5446,		"CLGD5446" },
	{ PCI_CHIP_GD5480,		"CLGD5480" },
	{ PCI_CHIP_GD5462,		"CL-GD5462" },
	{ PCI_CHIP_GD5464,		"CL-GD5464" },
	{ PCI_CHIP_GD5464BD,	"CL-GD5464BD" },
	{ PCI_CHIP_GD5465,		"CL-GD5465" },
	{ PCI_CHIP_GD7548,              "CL-GD7548" },
	{-1,					NULL }
};

/* List of PCI chipset names */
PciChipsets CIRPciChipsets[] = {
	{ PCI_CHIP_GD5430,	PCI_CHIP_GD5430,	RES_SHARED_VGA },
	{ PCI_CHIP_GD5434_4,PCI_CHIP_GD5434_4,	RES_SHARED_VGA },
	{ PCI_CHIP_GD5434_8,PCI_CHIP_GD5434_8,	RES_SHARED_VGA },
	{ PCI_CHIP_GD5436,	PCI_CHIP_GD5436,	RES_SHARED_VGA },
/*  { PCI_CHIP_GD5440,	PCI_CHIP_GD5440,	RES_SHARED_VGA }, */
	{ PCI_CHIP_GD5446,	PCI_CHIP_GD5446,	RES_SHARED_VGA },
	{ PCI_CHIP_GD5480,	PCI_CHIP_GD5480,	RES_SHARED_VGA },
	{ PCI_CHIP_GD5462,	PCI_CHIP_GD5462,	RES_SHARED_VGA },
	{ PCI_CHIP_GD5464,	PCI_CHIP_GD5464,	RES_SHARED_VGA },
	{ PCI_CHIP_GD5464BD,PCI_CHIP_GD5464BD,	RES_SHARED_VGA },
	{ PCI_CHIP_GD5465,	PCI_CHIP_GD5465,	RES_SHARED_VGA },
	{ PCI_CHIP_GD7548,	PCI_CHIP_GD7548,	RES_SHARED_VGA },
	{ -1,				-1,					RES_UNDEFINED}
};

/*
 * List of symbols from other modules that this module references.  This
 * list is used to tell the loader that it is OK for symbols here to be
 * unresolved providing that it hasn't been told that they haven't been
 * told that they are essential via a call to xf86LoaderReqSymbols() or
 * xf86LoaderReqSymLists().  The purpose of this is to avoid warnings about
 * unresolved symbols that are not required.
 */

static const char *alpSymbols[] = {
	"AlpAvailableOptions",
	"AlpProbe",
	NULL
};
static const char *lgSymbols[] = {
	"LgAvailableOptions",
	"LgProbe",
	NULL
};

static const char *vbeSymbols[] = {
	"VBEInit",
	"vbeDoEDID",
	"vbeFree",
	NULL
};

#ifdef XFree86LOADER

static MODULESETUPPROTO(cirSetup);

static XF86ModuleVersionInfo cirVersRec =
{
	"cirrus",
	MODULEVENDORSTRING,
	MODINFOSTRING1,
	MODINFOSTRING2,
	XORG_VERSION_CURRENT,
	CIR_MAJOR_VERSION, CIR_MINOR_VERSION, CIR_PATCHLEVEL,
	ABI_CLASS_VIDEODRV,			/* This is a video driver */
	ABI_VIDEODRV_VERSION,
	MOD_CLASS_VIDEODRV,
	{0,0,0,0}
};

/*
 * This is the module init data.
 * Its name has to be the driver name followed by ModuleData.
 */
_X_EXPORT XF86ModuleData cirrusModuleData = { &cirVersRec, cirSetup, NULL };

static pointer
cirSetup(pointer module, pointer opts, int *errmaj, int *errmin)
{
	static Bool setupDone = FALSE;

	/* This module should be loaded only once, but check to be sure. */

	if (!setupDone) {
		setupDone = TRUE;
		xf86AddDriver(&CIRRUS, module, 0);

		LoaderRefSymLists(alpSymbols, lgSymbols, vbeSymbols, NULL);
		return (pointer)1;
	}
	if (errmaj) *errmaj = LDR_ONCEONLY;
	return NULL;
}

#endif /* XFree86LOADER */

/* Mandatory */
static void
CIRIdentify(int flags)
{
	xf86PrintChipsets(CIR_NAME, "driver for Cirrus chipsets", CIRChipsets);
}

static const OptionInfoRec *
CIRAvailableOptions(int chipid, int busid)
{
	int chip = chipid & 0xffff;

        switch (chip)
	{
	case PCI_CHIP_GD5462:
	case PCI_CHIP_GD5464:
	case PCI_CHIP_GD5464BD:
	case PCI_CHIP_GD5465:
		if (lg_loaded)
			return LgAvailableOptions(chipid);
		else
			return NULL;

	default:
		if (alp_loaded)
			return AlpAvailableOptions(chipid);
		else
			return NULL;
	}
}

static Bool
CIRProbe(DriverPtr drv, int flags)
{
    int i;
    GDevPtr *devSections;
    pciVideoPtr pPci;
    int *usedChips;
    int numDevSections;
    int numUsed;
    Bool foundScreen = FALSE;
    ScrnInfoPtr pScrn;

#ifdef CIR_DEBUG
    ErrorF("CirProbe\n");
#endif
  
    /*
     * For PROBE_DETECT, make sure both sub-modules are loaded before
     * calling xf86MatchPciInstances(), because the AvailableOptions()
     * functions may be called before xf86MatchPciInstances() returns.
     */
    
    if (flags & PROBE_DETECT) {
	if (!lg_loaded) {
	    if (xf86LoadDrvSubModule(drv, "cirrus_laguna")) {
		xf86LoaderReqSymLists(lgSymbols, NULL);
		lg_loaded = TRUE;
	    }
	}
	if (!alp_loaded) {
	    if (xf86LoadDrvSubModule(drv, "cirrus_alpine")) {
		xf86LoaderReqSymLists(alpSymbols, NULL);
		alp_loaded = TRUE;
	    }
	}
    }

    if ((numDevSections = xf86MatchDevice(CIR_DRIVER_NAME,
					  &devSections)) <= 0) {
	return FALSE;
    }

#ifndef XSERVER_LIBPCIACCESS    
    if (xf86GetPciVideoInfo() == NULL) {
	/*
	 * We won't let anything in the config file override finding no
	 * PCI video cards at all.  This seems reasonable now, but we'll see.
	 */
	return FALSE;
    }
#endif
  
    numUsed = xf86MatchPciInstances(CIR_NAME, PCI_VENDOR_CIRRUS,
				    CIRChipsets, CIRPciChipsets, devSections,
 				    numDevSections, drv, &usedChips);
    /* Free it since we don't need that list after this */
    xfree(devSections);
    if (numUsed <= 0)
 	return FALSE;
    if (flags & PROBE_DETECT)
 	foundScreen = TRUE;
    else for (i = 0; i < numUsed; i++) {
 	/* The Laguna family of chips is so different from the Alpine
 	   family that we won't share even the highest-level of
 	   functions.  But, the Laguna chips /are/ Cirrus chips, so
 	   they should be handled in this driver (as opposed to their
 	   own driver). */
	pPci = xf86GetPciInfoForEntity(usedChips[i]);
	pScrn = NULL;
 	if (pPci && (PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5462 ||
		     PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5464 ||
		     PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5464BD ||
		     PCI_DEV_DEVICE_ID(pPci) == PCI_CHIP_GD5465)) {
 	    
 	    if (!lg_loaded) {
 		if (!xf86LoadDrvSubModule(drv, "cirrus_laguna")) 
		    continue;
 		xf86LoaderReqSymLists(lgSymbols, NULL);
 		lg_loaded = TRUE;
 	    }
	    pScrn = LgProbe(usedChips[i]);
 	} else {
 	    if (!alp_loaded) {
 		if (!xf86LoadDrvSubModule(drv, "cirrus_alpine")) 
 		    continue;
 		xf86LoaderReqSymLists(alpSymbols, NULL);
 		alp_loaded = TRUE;
 	    }
 	    pScrn = AlpProbe(usedChips[i]);
 	}
 	
 	if (pScrn) {
 	    foundScreen = TRUE;
 	    /* Fill in what we can of the ScrnInfoRec */
 	    pScrn->driverVersion = CIR_VERSION;
 	    pScrn->driverName	 = CIR_DRIVER_NAME;
 	    pScrn->name		 = CIR_NAME;
 	    pScrn->Probe	 = NULL;
 	}
    }
    xfree(usedChips);
     
    return foundScreen;
}

/*
 * Map the framebuffer and MMIO memory.
 */

Bool
CirMapMem(CirPtr pCir, int scrnIndex)
{
	int mmioFlags;

#ifdef CIR_DEBUG
	ErrorF("CirMapMem\n");
#endif

	/*
	 * Map the frame buffer.
	 */
	if (pCir->FbMapSize) {

#ifndef XSERVER_LIBPCIACCESS
	    
	    pCir->FbBase = xf86MapPciMem(scrnIndex, VIDMEM_FRAMEBUFFER,
					 pCir->PciTag, pCir->FbAddress,
					 pCir->FbMapSize);
	    if (pCir->FbBase == NULL)
		return FALSE;

#else
	    void** result = (void**)&pCir->FbBase;
	    int err = pci_device_map_range(pCir->PciInfo,
					   pCir->FbAddress,
					   pCir->FbMapSize,
					   PCI_DEV_MAP_FLAG_WRITABLE |
					   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
					   result);

	    if (err) 
	      return FALSE;
#endif
	}
	
#ifdef CIR_DEBUG
	ErrorF("CirMapMem pCir->FbBase=0x%08x\n", pCir->FbBase);
#endif

	/*
	 * Map IO registers to virtual address space
	 */
	if (pCir->IOAddress == 0) {
		pCir->IOBase = NULL; /* Until we are ready to use MMIO */
	} else {

#ifndef XSERVER_LIBPCIACCESS
		mmioFlags = VIDMEM_MMIO;
		/*
		 * For Alpha, we need to map SPARSE memory, since we need
		 * byte/short access.  Common-level will automatically use
		 * sparse mapping for MMIO.
		 */

		pCir->IOBase =
		  xf86MapPciMem(scrnIndex, mmioFlags, pCir->PciTag,
		       	        pCir->IOAddress, pCir->IoMapSize);
		if (pCir->IOBase == NULL)
			return FALSE;

#else
		void** result = (void**)&pCir->IOBase;
		int err = pci_device_map_range(pCir->PciInfo,
					       pCir->IOAddress,
					       pCir->IoMapSize,
					       PCI_DEV_MAP_FLAG_WRITABLE,
					       result);
		
		if (err) 
			return FALSE;
		
#endif
	}

#ifdef CIR_DEBUG
	ErrorF("CirMapMem pCir->IOBase=0x%08x [length=%08x] from PCI=%08x\n",
	       pCir->IOBase, pCir->IoMapSize, pCir->IOAddress);
	ErrorF("MMIO[GR31] = %2X\n", (int)
	       ((volatile unsigned char*) pCir->IOBase)[0x40]);
#endif

	return TRUE;
}


/*
 * Unmap the framebuffer and MMIO memory.
 */

Bool
CirUnmapMem(CirPtr pCir, int scrnIndex)
{
#ifdef CIR_DEBUG
	ErrorF("CirUnmapMem\n");
#endif

	if (pCir->IOBase != NULL) {
		/*
		 * Unmap IO registers to virtual address space
		 */
#ifndef XSERVER_LIBPCIACCESS
		xf86UnMapVidMem(scrnIndex, (pointer)pCir->IOBase, pCir->IoMapSize);
#else
		pci_device_unmap_range(pCir->PciInfo, (pointer)pCir->IOBase, pCir->IoMapSize);
#endif
		pCir->IOBase = NULL;
	}

#ifndef XSERVER_LIBPCIACCESS
	xf86UnMapVidMem(scrnIndex, (pointer)pCir->FbBase, pCir->FbMapSize);
#else
	pci_device_unmap_range(pCir->PciInfo, (pointer)pCir->FbBase, pCir->FbMapSize);
#endif
	pCir->FbBase = NULL;
	return TRUE;
}

void
cirProbeDDC(ScrnInfoPtr pScrn, int index)
{
    vbeInfoPtr pVbe;

    if (xf86LoadSubModule(pScrn, "vbe")) {
	xf86LoaderReqSymLists(vbeSymbols,NULL);
        pVbe = VBEInit(NULL,index);
        ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
	vbeFree(pVbe);
    }
}