#include "460gxPCI.h"
#include "xf86.h"
#include "Pci.h"
#define CBN 0x0040
#define DEVNPRES 0x0070
#define BUSNO 0x0048
#define SUBNO 0x0049
#define VGASE 0x0080
#define PCIS 0x0084
#define IOR 0x008C
#define IORD 0x008E
#define ERRCMD 0x0046
static int cbn_460gx = -1;
static CARD32 cbdevs_460gx = 0;
static CARD16 iord_460gx;
static int busno_460gx[8], subno_460gx[8];
static CARD8 pcis_460gx[8], ior_460gx[8];
static CARD8 has_err_460gx[8], err_460gx[8];
static CARD8 iomap_460gx[16];
static pciBusFuncs_t BusFuncs_460gx;
static pciConfigPtr
Verify460GXBus(int bus)
{
pciConfigPtr pPCI;
if ((bus < 0) || (bus >= pciNumBuses) ||
!pciBusInfo[bus] || !(pPCI = pciBusInfo[bus]->bridge) ||
(pPCI->busnum != cbn_460gx) || (pPCI->funcnum != 0) ||
(pPCI->devnum < 0x10) || (pPCI->devnum > 0x17))
return NULL;
return pPCI;
}
static CARD16
Control460GXBridge(int bus, CARD16 mask, CARD16 value)
{
pciConfigPtr pPCI;
PCITAG tag;
CARD16 current = 0;
CARD8 tmp;
if ((pPCI = Verify460GXBus(bus))) {
tmp = pciReadByte(pPCI->tag, VGASE);
if (tmp & 0x01) {
current |= PCI_PCI_BRIDGE_VGA_EN;
if ((mask & PCI_PCI_BRIDGE_VGA_EN) &&
!(value & PCI_PCI_BRIDGE_VGA_EN))
pciWriteByte(pPCI->tag, VGASE, tmp & ~0x01);
} else {
if (mask & value & PCI_PCI_BRIDGE_VGA_EN)
pciWriteByte(pPCI->tag, VGASE, tmp | 0x01);
}
if (has_err_460gx[pPCI->devnum - 0x10]) {
tag = PCI_MAKE_TAG(pPCI->busnum, pPCI->devnum, pPCI->funcnum + 1);
tmp = pciReadByte(tag, ERRCMD);
if (tmp & 0x01) {
current |= PCI_PCI_BRIDGE_MASTER_ABORT_EN;
if ((mask & PCI_PCI_BRIDGE_MASTER_ABORT_EN) &&
!(value & PCI_PCI_BRIDGE_MASTER_ABORT_EN))
pciWriteByte(tag, ERRCMD, tmp & ~0x01);
} else {
if (mask & value & PCI_PCI_BRIDGE_MASTER_ABORT_EN)
pciWriteByte(tag, ERRCMD, tmp | 0x01);
}
}
}
return (current & ~mask) | (value & mask);
}
static void
Get460GXBridgeBuses(int bus, int *primary, int *secondary, int *subordinate)
{
pciConfigPtr pPCI = Verify460GXBus(bus);
int i;
if (!pPCI)
return;
i = pPCI->devnum - 0x10;
if (primary)
*primary = pPCI->busnum;
if (secondary)
*secondary = busno_460gx[i];
if (subordinate)
*subordinate = subno_460gx[i];
}
static void
Get460GXBridgeResources(int bus,
pointer *ppIoRes,
pointer *ppMemRes,
pointer *ppPmemRes)
{
pciConfigPtr pPCI = Verify460GXBus(bus);
resRange range;
unsigned int i, j;
if (ppIoRes) {
xf86FreeResList(*ppIoRes);
*ppIoRes = NULL;
if (pPCI) {
for (i = 0; i <= 0x0F; i++) {
if (iomap_460gx[i] != pPCI->devnum)
continue;
RANGE(range, i << 12, ((i + 1) << 12) - 1,
RANGE_TYPE(ResExcIoBlock, 0));
*ppIoRes = xf86AddResToList(*ppIoRes, &range, -1);
}
}
}
if (ppMemRes) {
xf86FreeResList(*ppMemRes);
*ppMemRes = NULL;
if (pPCI) {
if (!(i = (pPCI->devnum - 0x10)))
j = 127;
else
j = pcis_460gx[i - 1] & 0x7F;
i = pcis_460gx[i] & 0x7F;
if (i < j) {
RANGE(range, i << 25, (j << 25) - 1,
RANGE_TYPE(ResExcMemBlock, 0));
*ppMemRes = xf86AddResToList(*ppMemRes, &range, -1);
}
}
}
if (ppPmemRes) {
xf86FreeResList(*ppPmemRes);
*ppPmemRes = NULL;
}
}
Bool
xf86PreScan460GX(void)
{
pciBusInfo_t *pBusInfo;
PCITAG tag;
CARD32 tmp;
int i, devno;
if (!(pBusInfo = pciBusInfo[0])) {
cbn_460gx = -1;
return FALSE;
}
tag = PCI_MAKE_TAG(0, 0x10, 0);
if (pciReadLong(tag, PCI_ID_REG) != DEVID(VENDOR_INTEL, CHIP_460GX_SAC)) {
cbn_460gx = -1;
return FALSE;
}
if (!(cbn_460gx = (unsigned int)pciReadByte(tag, CBN))) {
cbn_460gx = -1;
return TRUE;
}
if (pciNumBuses <= cbn_460gx)
pciNumBuses = cbn_460gx + 1;
if (!pciBusInfo[cbn_460gx]) {
pciBusInfo[cbn_460gx] = xnfalloc(sizeof(pciBusInfo_t));
*pciBusInfo[cbn_460gx] = *pBusInfo;
}
tag = PCI_MAKE_TAG(cbn_460gx, 0, 0);
if (pciReadLong(tag, PCI_ID_REG) != DEVID(VENDOR_INTEL, CHIP_460GX_SAC)) {
cbn_460gx = -1;
return TRUE;
}
cbdevs_460gx = pciReadLong(tag, DEVNPRES);
for (i = 0, devno = 0x10; devno <= 0x17; i++, devno++) {
tag = PCI_MAKE_TAG(cbn_460gx, devno, 0);
if (pciReadLong(tag, PCI_ID_REG) !=
DEVID(VENDOR_INTEL, CHIP_460GX_SAC)) {
cbn_460gx = -1;
return TRUE;
}
if (devno == 0x10)
iord_460gx = pciReadWord(tag, IORD);
busno_460gx[i] = (unsigned int)pciReadByte(tag, BUSNO);
subno_460gx[i] = (unsigned int)pciReadByte(tag, SUBNO);
pcis_460gx[i] = pciReadByte(tag, PCIS);
ior_460gx[i] = pciReadByte(tag, IOR);
has_err_460gx[i] = err_460gx[i] = 0;
tag = PCI_MAKE_TAG(cbn_460gx, devno, 1);
tmp = pciReadLong(tag, PCI_ID_REG);
switch (tmp) {
case DEVID(VENDOR_INTEL, CHIP_460GX_PXB):
case DEVID(VENDOR_INTEL, CHIP_460GX_WXB):
if (cbdevs_460gx & (1 << devno)) {
cbn_460gx = -1;
return TRUE;
}
err_460gx[i] = pciReadByte(tag, ERRCMD);
has_err_460gx[i] = 1;
break;
case DEVID(VENDOR_INTEL, CHIP_460GX_GXB_1):
if (cbdevs_460gx & (1 << devno)) {
cbn_460gx = -1;
return TRUE;
}
break;
default:
if (((CARD16)(tmp + 1U) <= (CARD16)1U) &&
(cbdevs_460gx & (1U << devno)))
break;
cbn_460gx = -1;
return TRUE;
}
}
for (i = 0, devno = 0x10; devno <= 0x17; i++, devno++) {
if (!(err_460gx[i] & 0x01))
continue;
pciWriteByte(PCI_MAKE_TAG(cbn_460gx, devno, 1),
ERRCMD, err_460gx[i] & ~0x01);
}
for (i = 0; subno_460gx[i] < cbn_460gx; ) {
if (++i < 8)
continue;
pciMaxBusNum = cbn_460gx + 1;
break;
}
return TRUE;
}
void
xf86PostScan460GX(void)
{
pciConfigPtr pPCI, *ppPCI;
pciBusInfo_t *pBusInfo;
int i, j, devno;
if (cbn_460gx <= 0)
return;
BusFuncs_460gx = *(pciBusInfo[0]->funcs);
BusFuncs_460gx.pciControlBridge = Control460GXBridge;
BusFuncs_460gx.pciGetBridgeBuses = Get460GXBridgeBuses;
BusFuncs_460gx.pciGetBridgeResources = Get460GXBridgeResources;
ppPCI = xf86scanpci(0);
while ((pPCI = *ppPCI++)) {
if ((pPCI->pci_base_class == PCI_CLASS_BRIDGE) &&
(pPCI->pci_sub_class == PCI_SUBCLASS_BRIDGE_HOST))
pPCI->businfo = HOST_NO_BUS;
}
ppPCI = xf86scanpci(0);
j = 0;
pBusInfo = pciBusInfo[cbn_460gx];
pBusInfo->bridge = pciBusInfo[0]->bridge;
while ((pPCI = *ppPCI++)) {
if (pPCI->busnum < cbn_460gx)
continue;
if (pPCI->busnum > cbn_460gx)
break;
if (pPCI->devnum < 0)
continue;
if (pPCI->devnum > 0)
break;
if (pPCI->funcnum < 0)
continue;
if (pPCI->funcnum > 0)
break;
pBusInfo->bridge = pPCI;
pBusInfo->secondary = FALSE;
pBusInfo->primary_bus = cbn_460gx;
break;
}
for (i = 0, devno = 0x10; devno <= 0x17; i++, devno++) {
if (err_460gx[i] & 0x01)
pciWriteByte(PCI_MAKE_TAG(cbn_460gx, devno, 1),
ERRCMD, err_460gx[i]);
if (!(cbdevs_460gx & (1 << devno))) {
while ((pPCI = *ppPCI++)) {
if (pPCI->busnum < cbn_460gx)
continue;
if (pPCI->busnum > cbn_460gx)
break;
if (pPCI->devnum < devno)
continue;
if (pPCI->devnum > devno)
break;
if (pPCI->funcnum < 0)
continue;
if (pPCI->funcnum > 0)
break;
if ((pBusInfo = pciBusInfo[busno_460gx[i]]))
break;
pBusInfo->bridge = pPCI;
pBusInfo->secondary = TRUE;
pBusInfo->primary_bus = cbn_460gx;
pBusInfo->funcs = &BusFuncs_460gx;
break;
}
}
for(; j <= (ior_460gx[i] & 0x0F); j++)
iomap_460gx[j] = devno;
}
iomap_460gx[0] = 0x10;
for (j = 1; j <= 0x0F; j++)
if (iord_460gx & (1 << j))
iomap_460gx[j] = 0x10;
}