#include <stdio.h>
#include "compiler.h"
#include "xf86.h"
#include "xf86Priv.h"
#include "Pci.h"
#ifdef PC98
#define outb(port,data) _outb(port,data)
#define outl(port,data) _outl(port,data)
#define inb(port) _inb(port)
#define inl(port) _inl(port)
#endif
#define PCI_CFGMECH2_ENABLE_REG 0xCF8
#ifdef PC98
#define PCI_CFGMECH2_FORWARD_REG 0xCF9
#else
#define PCI_CFGMECH2_FORWARD_REG 0xCFA
#endif
#define PCI_CFGMECH2_MAXDEV 16
#define PCI_ADDR_FROM_TAG_CFG1(tag,reg) (PCI_EN | tag | (reg & 0xfc))
#define PCI_FORWARD_FROM_TAG(tag) PCI_BUS_FROM_TAG(tag)
#define PCI_ENABLE_FROM_TAG(tag) (0xf0 | (((tag) & 0x00000700) >> 7))
#define PCI_ADDR_FROM_TAG_CFG2(tag,reg) (0xc000 | (((tag) & 0x0000f800) >> 3) \
| (reg & 0xfc))
static CARD32 ix86PciReadLongSetup(PCITAG tag, int off);
static void ix86PciWriteLongSetup(PCITAG, int off, CARD32 val);
static void ix86PciSetBitsLongSetup(PCITAG, int off, CARD32 mask, CARD32 val);
static CARD32 ix86PciReadLongCFG1(PCITAG tag, int off);
static void ix86PciWriteLongCFG1(PCITAG, int off, CARD32 val);
static void ix86PciSetBitsLongCFG1(PCITAG, int off, CARD32 mask, CARD32 val);
static CARD32 ix86PciReadLongCFG2(PCITAG tag, int off);
static void ix86PciWriteLongCFG2(PCITAG, int off, CARD32 val);
static void ix86PciSetBitsLongCFG2(PCITAG, int off, CARD32 mask, CARD32 val);
static pciBusFuncs_t ix86Funcs0 = {
ix86PciReadLongSetup,
ix86PciWriteLongSetup,
ix86PciSetBitsLongSetup,
pciAddrNOOP,
pciAddrNOOP
};
static pciBusFuncs_t ix86Funcs1 = {
ix86PciReadLongCFG1,
ix86PciWriteLongCFG1,
ix86PciSetBitsLongCFG1,
pciAddrNOOP,
pciAddrNOOP
};
static pciBusFuncs_t ix86Funcs2 = {
ix86PciReadLongCFG2,
ix86PciWriteLongCFG2,
ix86PciSetBitsLongCFG2,
pciAddrNOOP,
pciAddrNOOP
};
static pciBusInfo_t ix86Pci0 = {
PCI_CFG_MECH_UNKNOWN,
0,
FALSE,
0,
#ifdef PowerMAX_OS
0,
0,
#endif
&ix86Funcs0,
NULL,
NULL
};
static Bool
ix86PciBusCheck(void)
{
PCITAG tag;
CARD32 id, class;
CARD8 device;
for (device = 0; device < ix86Pci0.numDevices; device++) {
tag = PCI_MAKE_TAG(0, device, 0);
id = (*ix86Pci0.funcs->pciReadLong)(tag, PCI_ID_REG);
if ((CARD16)(id + 1U) <= (CARD16)1UL)
continue;
class = (*ix86Pci0.funcs->pciReadLong)(tag, PCI_CLASS_REG);
switch (class >> 16) {
case (PCI_CLASS_PREHISTORIC << 8) | PCI_SUBCLASS_PREHISTORIC_MISC:
id &= 0x0000ffff;
if ((id == PCI_VENDOR_INTEL) || (id == PCI_VENDOR_COMPAQ))
return TRUE;
continue;
case (PCI_CLASS_PREHISTORIC << 8) | PCI_SUBCLASS_PREHISTORIC_VGA:
case (PCI_CLASS_DISPLAY << 8) | PCI_SUBCLASS_DISPLAY_VGA:
case (PCI_CLASS_BRIDGE << 8) | PCI_SUBCLASS_BRIDGE_HOST:
return TRUE;
default:
break;
}
}
return FALSE;
}
static
void ix86PciSelectCfgmech(void)
{
static Bool beenhere = FALSE;
CARD32 mode1Res1 = 0, mode1Res2 = 0, oldVal1 = 0;
CARD8 mode2Res1 = 0, mode2Res2 = 0, oldVal2 = 0;
int stages = 0;
if (beenhere)
return;
beenhere = TRUE;
switch (xf86Info.pciFlags) {
case PCIProbe1:
xf86MsgVerb(X_INFO, 2, "PCI: Probing config type using method 1\n");
oldVal1 = inl(PCI_CFGMECH1_ADDRESS_REG);
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("Checking config type 1:\n"
"\tinitial value of MODE1_ADDR_REG is 0x%08x\n", oldVal1);
ErrorF("\tChecking that all bits in mask 0x7f000000 are clear\n");
}
#endif
if ((oldVal1 & 0x7f000000) == 0) {
stages |= 0x01;
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("\tValue indicates possibly config type 1\n");
ErrorF("\tWriting 32-bit value 0x%08x to MODE1_ADDR_REG\n", PCI_EN);
#if 0
ErrorF("\tWriting 8-bit value 0x00 to MODE1_ADDR_REG + 3\n");
#endif
}
#endif
ix86Pci0.configMech = PCI_CFG_MECH_1;
ix86Pci0.numDevices = PCI_CFGMECH1_MAXDEV;
ix86Pci0.funcs = &ix86Funcs1;
outl(PCI_CFGMECH1_ADDRESS_REG, PCI_EN);
#if 0
outb(PCI_CFGMECH1_ADDRESS_REG + 3, 0);
#endif
mode1Res1 = inl(PCI_CFGMECH1_ADDRESS_REG);
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("\tValue read back from MODE1_ADDR_REG is 0x%08x\n",
mode1Res1);
ErrorF("\tRestoring original contents of MODE1_ADDR_REG\n");
}
#endif
outl(PCI_CFGMECH1_ADDRESS_REG, oldVal1);
if (mode1Res1) {
stages |= 0x02;
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("\tValue read back is non-zero, and indicates possible"
" config type 1\n");
}
#endif
if (ix86PciBusCheck()) {
#ifdef DEBUGPCI
if (xf86Verbose > 2)
ErrorF("\tBus check Confirms this: ");
#endif
xf86MsgVerb(X_INFO, 2, "PCI: Config type is 1\n");
xf86MsgVerb(X_INFO, 3,
"PCI: stages = 0x%02x, oldVal1 = 0x%08lx, mode1Res1"
" = 0x%08lx\n", stages, (unsigned long)oldVal1,
(unsigned long)mode1Res1);
return;
}
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("\tBus check fails to confirm this, continuing type 1"
" check ...\n");
}
#endif
}
stages |= 0x04;
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("\tWriting 0xff000001 to MODE1_ADDR_REG\n");
}
#endif
outl(PCI_CFGMECH1_ADDRESS_REG, 0xff000001);
mode1Res2 = inl(PCI_CFGMECH1_ADDRESS_REG);
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("\tValue read back from MODE1_ADDR_REG is 0x%08x\n",
mode1Res2);
ErrorF("\tRestoring original contents of MODE1_ADDR_REG\n");
}
#endif
outl(PCI_CFGMECH1_ADDRESS_REG, oldVal1);
if ((mode1Res2 & 0x80000001) == 0x80000000) {
stages |= 0x08;
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("\tValue read back has only the msb set\n"
"\tThis indicates possible config type 1\n");
}
#endif
if (ix86PciBusCheck()) {
#ifdef DEBUGPCI
if (xf86Verbose > 2)
ErrorF("\tBus check Confirms this: ");
#endif
xf86MsgVerb(X_INFO, 2, "PCI: Config type is 1\n");
xf86MsgVerb(X_INFO, 3,
"PCI: stages = 0x%02x, oldVal1 = 0x%08lx,\n"
"\tmode1Res1 = 0x%08lx, mode1Res2 = 0x%08lx\n",
stages, (unsigned long)oldVal1,
(unsigned long)mode1Res1, (unsigned long)mode1Res2);
return;
}
#ifdef DEBUGPCI
if (xf86Verbose > 2) {
ErrorF("\tBus check fails to confirm this.\n");
}
#endif
}
}
xf86MsgVerb(X_INFO, 3, "PCI: Standard check for type 1 failed.\n");
xf86MsgVerb(X_INFO, 3, "PCI: stages = 0x%02x, oldVal1 = 0x%08lx,\n"
"\tmode1Res1 = 0x%08lx, mode1Res2 = 0x%08lx\n",
stages, (unsigned long)oldVal1, (unsigned long)mode1Res1,
(unsigned long)mode1Res2);
oldVal2 = inb(PCI_CFGMECH2_ENABLE_REG);
if ((oldVal2 & 0xf0) == 0) {
ix86Pci0.configMech = PCI_CFG_MECH_2;
ix86Pci0.numDevices = PCI_CFGMECH2_MAXDEV;
ix86Pci0.funcs = &ix86Funcs2;
outb(PCI_CFGMECH2_ENABLE_REG, 0x0e);
mode2Res1 = inb(PCI_CFGMECH2_ENABLE_REG);
outb(PCI_CFGMECH2_ENABLE_REG, oldVal2);
if (mode2Res1 == 0x0e) {
if (ix86PciBusCheck()) {
xf86MsgVerb(X_INFO, 2, "PCI: Config type is 2\n");
return;
}
}
}
break;
case PCIProbe2:
xf86MsgVerb(X_INFO, 2, "PCI: Probing config type using method 2\n");
outb(PCI_CFGMECH2_ENABLE_REG, 0x00);
outb(PCI_CFGMECH2_FORWARD_REG, 0x00);
mode2Res1 = inb(PCI_CFGMECH2_ENABLE_REG);
mode2Res2 = inb(PCI_CFGMECH2_FORWARD_REG);
if (mode2Res1 == 0 && mode2Res2 == 0) {
xf86MsgVerb(X_INFO, 2, "PCI: Config type is 2\n");
ix86Pci0.configMech = PCI_CFG_MECH_2;
ix86Pci0.numDevices = PCI_CFGMECH2_MAXDEV;
ix86Pci0.funcs = &ix86Funcs2;
return;
}
oldVal1 = inl(PCI_CFGMECH1_ADDRESS_REG);
outl(PCI_CFGMECH1_ADDRESS_REG, PCI_EN);
mode1Res1 = inl(PCI_CFGMECH1_ADDRESS_REG);
outl(PCI_CFGMECH1_ADDRESS_REG, oldVal1);
if (mode1Res1 == PCI_EN) {
xf86MsgVerb(X_INFO, 2, "PCI: Config type is 1\n");
ix86Pci0.configMech = PCI_CFG_MECH_1;
ix86Pci0.numDevices = PCI_CFGMECH1_MAXDEV;
ix86Pci0.funcs = &ix86Funcs1;
return;
}
break;
case PCIForceConfig1:
xf86MsgVerb(X_INFO, 2, "PCI: Forcing config type 1\n");
ix86Pci0.configMech = PCI_CFG_MECH_1;
ix86Pci0.numDevices = PCI_CFGMECH1_MAXDEV;
ix86Pci0.funcs = &ix86Funcs1;
return;
case PCIForceConfig2:
xf86MsgVerb(X_INFO, 2, "PCI: Forcing config type 2\n");
ix86Pci0.configMech = PCI_CFG_MECH_2;
ix86Pci0.numDevices = PCI_CFGMECH2_MAXDEV;
ix86Pci0.funcs = &ix86Funcs2;
return;
case PCIOsConfig:
return;
case PCIForceNone:
break;
}
ix86Pci0.configMech = PCI_CFG_MECH_UNKNOWN;
xf86MsgVerb(X_INFO, 2, "PCI: No PCI bus found or probed for\n");
}
#if 0
static pciTagRec
ix86PcibusTag(CARD8 bus, CARD8 cardnum, CARD8 func)
{
pciTagRec tag;
tag.cfg1 = 0;
if (func > 7 || cardnum >= pciBusInfo[bus]->numDevices)
return tag;
switch (ix86Pci0.configMech) {
case PCI_CFG_MECH_1:
tag.cfg1 = PCI_EN | ((CARD32)bus << 16) |
((CARD32)cardnum << 11) |
((CARD32)func << 8);
break;
case PCI_CFG_MECH_2:
tag.cfg2.port = 0xc000 | ((CARD16)cardnum << 8);
tag.cfg2.enable = 0xf0 | (func << 1);
tag.cfg2.forward = bus;
break;
}
return tag;
}
#endif
static CARD32
ix86PciReadLongSetup(PCITAG Tag, int reg)
{
ix86PciSelectCfgmech();
return (*ix86Pci0.funcs->pciReadLong)(Tag,reg);
}
static CARD32
ix86PciReadLongCFG1(PCITAG Tag, int reg)
{
CARD32 addr, data = 0;
#ifdef DEBUGPCI
ErrorF("ix86PciReadLong 0x%lx, %d\n", Tag, reg);
#endif
addr = PCI_ADDR_FROM_TAG_CFG1(Tag,reg);
outl(PCI_CFGMECH1_ADDRESS_REG, addr);
data = inl(PCI_CFGMECH1_DATA_REG);
outl(PCI_CFGMECH1_ADDRESS_REG, 0);
#ifdef DEBUGPCI
ErrorF("ix86PciReadLong 0x%lx\n", data);
#endif
return data;
}
static CARD32
ix86PciReadLongCFG2(PCITAG Tag, int reg)
{
CARD32 addr, data = 0;
CARD8 forward, enable;
#ifdef DEBUGPCI
ErrorF("ix86PciReadLong 0x%lx, %d\n", Tag, reg);
#endif
forward = PCI_FORWARD_FROM_TAG(Tag);
enable = PCI_ENABLE_FROM_TAG(Tag);
addr = PCI_ADDR_FROM_TAG_CFG2(Tag,reg);
outb(PCI_CFGMECH2_ENABLE_REG, enable);
outb(PCI_CFGMECH2_FORWARD_REG, forward);
data = inl((CARD16)addr);
outb(PCI_CFGMECH2_ENABLE_REG, 0);
outb(PCI_CFGMECH2_FORWARD_REG, 0);
#ifdef DEBUGPCI
ErrorF("ix86PciReadLong 0x%lx\n", data);
#endif
return data;
}
static void
ix86PciWriteLongSetup(PCITAG Tag, int reg, CARD32 data)
{
ix86PciSelectCfgmech();
(*ix86Pci0.funcs->pciWriteLong)(Tag,reg,data);
}
static void
ix86PciWriteLongCFG1(PCITAG Tag, int reg, CARD32 data)
{
CARD32 addr;
addr = PCI_ADDR_FROM_TAG_CFG1(Tag,reg);
outl(PCI_CFGMECH1_ADDRESS_REG, addr);
outl(PCI_CFGMECH1_DATA_REG, data);
outl(PCI_CFGMECH1_ADDRESS_REG, 0);
}
static void
ix86PciWriteLongCFG2(PCITAG Tag, int reg, CARD32 data)
{
CARD32 addr;
CARD8 forward, enable;
forward = PCI_FORWARD_FROM_TAG(Tag);
enable = PCI_ENABLE_FROM_TAG(Tag);
addr = PCI_ADDR_FROM_TAG_CFG2(Tag,reg);
outb(PCI_CFGMECH2_ENABLE_REG, enable);
outb(PCI_CFGMECH2_FORWARD_REG, forward);
outl((CARD16)addr, data);
outb(PCI_CFGMECH2_ENABLE_REG, 0);
outb(PCI_CFGMECH2_FORWARD_REG, 0);
}
static void
ix86PciSetBitsLongSetup(PCITAG Tag, int reg, CARD32 mask, CARD32 val)
{
ix86PciSelectCfgmech();
(*ix86Pci0.funcs->pciSetBitsLong)(Tag,reg,mask,val);
}
static void
ix86PciSetBitsLongCFG1(PCITAG Tag, int reg, CARD32 mask, CARD32 val)
{
CARD32 addr, data = 0;
#ifdef DEBUGPCI
ErrorF("ix86PciSetBitsLong 0x%lx, %d\n", Tag, reg);
#endif
addr = PCI_ADDR_FROM_TAG_CFG1(Tag,reg);
outl(PCI_CFGMECH1_ADDRESS_REG, addr);
data = inl(PCI_CFGMECH1_DATA_REG);
data = (data & ~mask) | (val & mask);
outl(PCI_CFGMECH1_DATA_REG, data);
outl(PCI_CFGMECH1_ADDRESS_REG, 0);
}
static void
ix86PciSetBitsLongCFG2(PCITAG Tag, int reg, CARD32 mask, CARD32 val)
{
CARD32 addr, data = 0;
CARD8 enable, forward;
#ifdef DEBUGPCI
ErrorF("ix86PciSetBitsLong 0x%lx, %d\n", Tag, reg);
#endif
forward = PCI_FORWARD_FROM_TAG(Tag);
enable = PCI_ENABLE_FROM_TAG(Tag);
addr = PCI_ADDR_FROM_TAG_CFG2(Tag,reg);
outb(PCI_CFGMECH2_ENABLE_REG, enable);
outb(PCI_CFGMECH2_FORWARD_REG, forward);
data = inl((CARD16)addr);
data = (data & ~mask) | (val & mask);
outl((CARD16)addr, data);
outb(PCI_CFGMECH2_ENABLE_REG, 0);
outb(PCI_CFGMECH2_FORWARD_REG, 0);
}
void
ix86PciInit()
{
pciNumBuses = 1;
pciBusInfo[0] = &ix86Pci0;
pciFindFirstFP = pciGenFindFirst;
pciFindNextFP = pciGenFindNext;
ix86PciSelectCfgmech();
if (ix86Pci0.configMech == PCI_CFG_MECH_UNKNOWN) {
pciNumBuses = 0;
pciBusInfo[0] = NULL;
}
}