First import
[xorg_rtime.git] / xorg-server-1.4 / hw / xfree86 / os-support / bus / 460gxPCI.c
blob44ee9768714d74aa0344e47a2f3171ad7ea58471
1 /*
2 * Copyright (C) 2002-2003 The XFree86 Project, Inc. All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 * Except as contained in this notice, the name of the XFree86 Project shall
22 * not be used in advertising or otherwise to promote the sale, use or other
23 * dealings in this Software without prior written authorization from the
24 * XFree86 Project.
28 * This file contains the glue necessary for support of Intel's 460GX chipset.
31 #ifdef HAVE_XORG_CONFIG_H
32 #include <xorg-config.h>
33 #endif
35 #include "460gxPCI.h"
36 #include "xf86.h"
37 #include "Pci.h"
39 /* 460GX register definitions */
40 /* SAC at 0:10:0 */
41 #define CBN 0x0040
42 /* SAC at CBN:0:0 */
43 #define DEVNPRES 0x0070
44 /* SAC at CBN:1[0-7]:0 */
45 #define BUSNO 0x0048
46 #define SUBNO 0x0049
47 #define VGASE 0x0080
48 #define PCIS 0x0084
49 #define IOR 0x008C
50 #define IORD 0x008E /* CBN:10:0 only */
51 /* PXB at CBN:1[0-7]:1 */
52 #define ERRCMD 0x0046
54 static int cbn_460gx = -1;
55 static CARD32 cbdevs_460gx = 0;
56 static CARD16 iord_460gx;
57 static int busno_460gx[8], subno_460gx[8];
58 static CARD8 pcis_460gx[8], ior_460gx[8];
59 static CARD8 has_err_460gx[8], err_460gx[8];
60 static CARD8 iomap_460gx[16]; /* One for each 4k */
61 static pciBusFuncs_t BusFuncs_460gx;
63 static pciConfigPtr
64 Verify460GXBus(int bus)
66 pciConfigPtr pPCI;
68 if ((bus < 0) || (bus >= pciNumBuses) ||
69 !pciBusInfo[bus] || !(pPCI = pciBusInfo[bus]->bridge) ||
70 (pPCI->busnum != cbn_460gx) || (pPCI->funcnum != 0) ||
71 (pPCI->devnum < 0x10) || (pPCI->devnum > 0x17))
72 return NULL;
74 return pPCI;
78 * This function is called to emulate the various settings in a P2P or CardBus
79 * bridge's control register using one of a 460GX's SAC host bridges.
81 static CARD16
82 Control460GXBridge(int bus, CARD16 mask, CARD16 value)
84 pciConfigPtr pPCI;
85 PCITAG tag;
86 CARD16 current = 0;
87 CARD8 tmp;
89 if ((pPCI = Verify460GXBus(bus))) {
90 /* Start with VGA enablement */
91 tmp = pciReadByte(pPCI->tag, VGASE);
92 if (tmp & 0x01) {
93 current |= PCI_PCI_BRIDGE_VGA_EN;
94 if ((mask & PCI_PCI_BRIDGE_VGA_EN) &&
95 !(value & PCI_PCI_BRIDGE_VGA_EN))
96 pciWriteByte(pPCI->tag, VGASE, tmp & ~0x01);
97 } else {
98 if (mask & value & PCI_PCI_BRIDGE_VGA_EN)
99 pciWriteByte(pPCI->tag, VGASE, tmp | 0x01);
102 /* Move on to master abort failure enablement */
103 if (has_err_460gx[pPCI->devnum - 0x10]) {
104 tag = PCI_MAKE_TAG(pPCI->busnum, pPCI->devnum, pPCI->funcnum + 1);
105 tmp = pciReadByte(tag, ERRCMD);
106 if (tmp & 0x01) {
107 current |= PCI_PCI_BRIDGE_MASTER_ABORT_EN;
108 if ((mask & PCI_PCI_BRIDGE_MASTER_ABORT_EN) &&
109 !(value & PCI_PCI_BRIDGE_MASTER_ABORT_EN))
110 pciWriteByte(tag, ERRCMD, tmp & ~0x01);
111 } else {
112 if (mask & value & PCI_PCI_BRIDGE_MASTER_ABORT_EN)
113 pciWriteByte(tag, ERRCMD, tmp | 0x01);
117 /* Put emulation of any other P2P bridge control here */
120 return (current & ~mask) | (value & mask);
124 * Retrieve various bus numbers representing the connections provided by 460GX
125 * host bridges.
127 static void
128 Get460GXBridgeBuses(int bus, int *primary, int *secondary, int *subordinate)
130 pciConfigPtr pPCI = Verify460GXBus(bus);
131 int i;
133 /* The returned bus numbers are initialised by the caller */
135 if (!pPCI)
136 return;
138 i = pPCI->devnum - 0x10;
140 /* These are not modified, so no need to re-read them */
141 if (primary)
142 *primary = pPCI->busnum;
143 if (secondary)
144 *secondary = busno_460gx[i];
145 if (subordinate)
146 *subordinate = subno_460gx[i];
149 /* Retrieves a list of the resources routed to a host bridge's secondary bus */
150 static void
151 Get460GXBridgeResources(int bus,
152 pointer *ppIoRes,
153 pointer *ppMemRes,
154 pointer *ppPmemRes)
156 pciConfigPtr pPCI = Verify460GXBus(bus);
157 resRange range;
158 unsigned int i, j;
160 if (ppIoRes) {
161 xf86FreeResList(*ppIoRes);
162 *ppIoRes = NULL;
164 if (pPCI) {
165 for (i = 0; i <= 0x0F; i++) {
166 if (iomap_460gx[i] != pPCI->devnum)
167 continue;
169 RANGE(range, i << 12, ((i + 1) << 12) - 1,
170 RANGE_TYPE(ResExcIoBlock, 0));
171 *ppIoRes = xf86AddResToList(*ppIoRes, &range, -1);
176 if (ppMemRes) {
177 xf86FreeResList(*ppMemRes);
178 *ppMemRes = NULL;
180 if (pPCI) {
181 if (!(i = (pPCI->devnum - 0x10)))
182 j = 127; /* (4GB - 32M) / 32M */
183 else
184 j = pcis_460gx[i - 1] & 0x7F;
186 i = pcis_460gx[i] & 0x7F;
187 if (i < j) {
188 RANGE(range, i << 25, (j << 25) - 1,
189 RANGE_TYPE(ResExcMemBlock, 0));
190 *ppMemRes = xf86AddResToList(*ppMemRes, &range, -1);
195 if (ppPmemRes) {
196 xf86FreeResList(*ppPmemRes);
197 *ppPmemRes = NULL;
202 * This checks for, and validates, the presence of the 460GX chipset, and sets
203 * cbn_460gx to a positive value accordingly. This function returns TRUE if
204 * the chipset scan is to be stopped, or FALSE if the scan is to move on to the
205 * next chipset.
208 Bool
209 xorgProbe460GX(scanpciWrapperOpt flags)
211 pciBusInfo_t *pBusInfo;
212 PCITAG tag;
214 /* Bus zero should already be set up */
215 if (!(pBusInfo = pciBusInfo[0])) {
216 cbn_460gx = -1;
217 return FALSE;
219 /* First look for a 460GX's primary host bridge */
220 tag = PCI_MAKE_TAG(0, 0x10, 0);
221 if (pciReadLong(tag, PCI_ID_REG) == DEVID(VENDOR_INTEL, CHIP_460GX_SAC)) {
222 return TRUE;
225 cbn_460gx = -1;
227 return FALSE;
230 void
231 xf86PreScan460GX(void)
233 pciBusInfo_t *pBusInfo;
234 PCITAG tag;
235 CARD32 tmp;
236 int i, devno;
238 if (!(pBusInfo = pciBusInfo[0]))
239 return;
241 /* Get CBN (Chipset bus number) */
242 tag = PCI_MAKE_TAG(0, 0x10, 0);
243 if (!(cbn_460gx = (unsigned int)pciReadByte(tag, CBN))) {
244 /* Sanity check failed */
245 cbn_460gx = -1;
246 return;
249 if (pciNumBuses <= cbn_460gx)
250 pciNumBuses = cbn_460gx + 1;
252 /* Set up bus CBN */
253 if (!pciBusInfo[cbn_460gx]) {
254 pciBusInfo[cbn_460gx] = xnfalloc(sizeof(pciBusInfo_t));
255 *pciBusInfo[cbn_460gx] = *pBusInfo;
258 tag = PCI_MAKE_TAG(cbn_460gx, 0, 0);
259 if (pciReadLong(tag, PCI_ID_REG) != DEVID(VENDOR_INTEL, CHIP_460GX_SAC)) {
260 /* Sanity check failed */
261 cbn_460gx = -1;
262 return;
266 * Find out which CBN devices the firmware thinks are present. Of these,
267 * we are only interested in devices 0x10 through 0x17.
269 cbdevs_460gx = pciReadLong(tag, DEVNPRES);
271 for (i = 0, devno = 0x10; devno <= 0x17; i++, devno++) {
272 tag = PCI_MAKE_TAG(cbn_460gx, devno, 0);
273 if (pciReadLong(tag, PCI_ID_REG) !=
274 DEVID(VENDOR_INTEL, CHIP_460GX_SAC)) {
275 /* Sanity check failed */
276 cbn_460gx = -1;
277 return;
280 if (devno == 0x10)
281 iord_460gx = pciReadWord(tag, IORD);
283 busno_460gx[i] = (unsigned int)pciReadByte(tag, BUSNO);
284 subno_460gx[i] = (unsigned int)pciReadByte(tag, SUBNO);
285 pcis_460gx[i] = pciReadByte(tag, PCIS);
286 ior_460gx[i] = pciReadByte(tag, IOR);
288 has_err_460gx[i] = err_460gx[i] = 0; /* Insurance */
290 tag = PCI_MAKE_TAG(cbn_460gx, devno, 1);
291 tmp = pciReadLong(tag, PCI_ID_REG);
292 switch (tmp) {
293 case DEVID(VENDOR_INTEL, CHIP_460GX_PXB):
294 case DEVID(VENDOR_INTEL, CHIP_460GX_WXB):
295 if (cbdevs_460gx & (1 << devno)) {
296 /* Sanity check failed */
297 cbn_460gx = -1;
298 return;
302 * XXX I don't have WXB docs, but PCI register dumps indicate that
303 * the registers we are interested in are consistent with those of
304 * the PXB.
306 err_460gx[i] = pciReadByte(tag, ERRCMD);
307 has_err_460gx[i] = 1;
308 break;
310 case DEVID(VENDOR_INTEL, CHIP_460GX_GXB_1):
311 if (cbdevs_460gx & (1 << devno)) {
312 /* Sanity check failed */
313 cbn_460gx = -1;
314 return;
318 * XXX GXB isn't documented to have an ERRCMD register, nor any
319 * other means of failing master aborts. For now, assume master
320 * aborts are always allowed to complete normally.
322 break;
324 default:
325 if (((CARD16)(tmp + 1U) <= (CARD16)1U) &&
326 (cbdevs_460gx & (1U << devno)))
327 break;
328 /* Sanity check failed */
329 cbn_460gx = -1;
330 return;
334 /* Allow master aborts to complete normally */
335 for (i = 0, devno = 0x10; devno <= 0x17; i++, devno++) {
336 if (!(err_460gx[i] & 0x01))
337 continue;
339 pciWriteByte(PCI_MAKE_TAG(cbn_460gx, devno, 1),
340 ERRCMD, err_460gx[i] & ~0x01);
344 * The 460GX spec says that any access to buses higher than CBN will be
345 * master-aborted. It seems possible however that this is not the case in
346 * all 460GX implementations. For now, limit the bus scan to CBN, unless
347 * we have already found a higher bus number.
349 for (i = 0; subno_460gx[i] < cbn_460gx; ) {
350 if (++i < 8)
351 continue;
353 pciMaxBusNum = cbn_460gx + 1;
354 break;
357 return;
360 /* This does some 460GX-related processing after the PCI bus scan */
361 void
362 xf86PostScan460GX(void)
364 pciConfigPtr pPCI, *ppPCI;
365 pciBusInfo_t *pBusInfo;
366 int i, j, devno;
368 if (cbn_460gx <= 0)
369 return;
371 /* Set up our extra bus functions */
372 BusFuncs_460gx = *(pciBusInfo[0]->funcs);
373 BusFuncs_460gx.pciControlBridge = Control460GXBridge;
374 BusFuncs_460gx.pciGetBridgeBuses = Get460GXBridgeBuses;
375 BusFuncs_460gx.pciGetBridgeResources = Get460GXBridgeResources;
378 * Mark all host bridges so that they are ignored by the upper-level
379 * xf86GetPciBridgeInfo() function. This marking is later clobbered by the
380 * tail end of xf86scanpci() for those bridges that actually have bus
381 * segments associated with them.
383 ppPCI = xf86scanpci(0); /* Recursion is only apparent */
384 while ((pPCI = *ppPCI++)) {
385 if ((pPCI->pci_base_class == PCI_CLASS_BRIDGE) &&
386 (pPCI->pci_sub_class == PCI_SUBCLASS_BRIDGE_HOST))
387 pPCI->businfo = HOST_NO_BUS;
390 ppPCI = xf86scanpci(0); /* Recursion is only apparent */
391 j = 0;
394 * Fix up CBN bus linkage. This is somewhat arbitrary. The bridge chosen
395 * for this must be a CBN device so that bus CBN can be recognised as the
396 * root segment. It also cannot be any of the bus expanders (devices
397 * CBN:0x10:0 through CBN:0x17:0 nor any of their functions). For now, we
398 * chose the SAC host bridge at CBN:0:0.
400 pBusInfo = pciBusInfo[cbn_460gx];
401 pBusInfo->bridge = pciBusInfo[0]->bridge; /* Just in case */
402 while ((pPCI = *ppPCI++)) {
403 if (pPCI->busnum < cbn_460gx)
404 continue;
405 if (pPCI->busnum > cbn_460gx)
406 break;
407 if (pPCI->devnum < 0)
408 continue;
409 if (pPCI->devnum > 0)
410 break;
411 if (pPCI->funcnum < 0)
412 continue;
413 if (pPCI->funcnum > 0)
414 break;
416 pBusInfo->bridge = pPCI;
417 pBusInfo->secondary = FALSE;
418 pBusInfo->primary_bus = cbn_460gx;
419 break;
422 for (i = 0, devno = 0x10; devno <= 0x17; i++, devno++) {
423 /* Restore ERRCMD registers */
424 if (err_460gx[i] & 0x01)
425 pciWriteByte(PCI_MAKE_TAG(cbn_460gx, devno, 1),
426 ERRCMD, err_460gx[i]);
428 if (!(cbdevs_460gx & (1 << devno))) {
429 while ((pPCI = *ppPCI++)) {
430 if (pPCI->busnum < cbn_460gx)
431 continue;
432 if (pPCI->busnum > cbn_460gx)
433 break;
434 if (pPCI->devnum < devno)
435 continue;
436 if (pPCI->devnum > devno)
437 break;
438 if (pPCI->funcnum < 0)
439 continue;
440 if (pPCI->funcnum > 0)
441 break;
443 if ((pBusInfo == pciBusInfo[busno_460gx[i]]))
444 break;
446 /* Fix bus linkage */
447 pBusInfo->bridge = pPCI;
448 pBusInfo->secondary = TRUE;
449 pBusInfo->primary_bus = cbn_460gx;
451 /* Plug in chipset routines */
452 pBusInfo->funcs = &BusFuncs_460gx;
453 break;
457 /* Decode IOR registers */
458 for(; j <= (ior_460gx[i] & 0x0F); j++)
459 iomap_460gx[j] = devno;
462 /* The bottom 4k of I/O space is always routed to PCI0a */
463 iomap_460gx[0] = 0x10;
465 /* Decode IORD register */
466 for (j = 1; j <= 0x0F; j++)
467 if (iord_460gx & (1 << j))
468 iomap_460gx[j] = 0x10;