From f4092abdf94af6a99aff944d6264bc1284e8bdd4 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Mon, 10 Oct 2011 17:43:39 +0200 Subject: Imported nx-X11-3.1.0-1.tar.gz Summary: Imported nx-X11-3.1.0-1.tar.gz Keywords: Imported nx-X11-3.1.0-1.tar.gz into Git repository --- .../Xserver/hw/xfree86/os-support/pmax/pmax_pci.c | 1072 ++++++++++++++++++++ 1 file changed, 1072 insertions(+) create mode 100644 nx-X11/programs/Xserver/hw/xfree86/os-support/pmax/pmax_pci.c (limited to 'nx-X11/programs/Xserver/hw/xfree86/os-support/pmax/pmax_pci.c') diff --git a/nx-X11/programs/Xserver/hw/xfree86/os-support/pmax/pmax_pci.c b/nx-X11/programs/Xserver/hw/xfree86/os-support/pmax/pmax_pci.c new file mode 100644 index 000000000..21f20dff8 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/xfree86/os-support/pmax/pmax_pci.c @@ -0,0 +1,1072 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/pmax/pmax_pci.c,v 1.6 2002/07/24 19:06:53 tsi Exp $ */ +/* + * Copyright 1998 by Concurrent Computer Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Concurrent Computer + * Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Concurrent Computer Corporation makes no representations + * about the suitability of this software for any purpose. It is + * provided "as is" without express or implied warranty. + * + * CONCURRENT COMPUTER CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CONCURRENT COMPUTER CORPORATION BE + * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Copyright 1998 by Metro Link Incorporated + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Metro Link + * Incorporated not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Metro Link Incorporated makes no representations + * about the suitability of this software for any purpose. It is + * provided "as is" without express or implied warranty. + * + * METRO LINK INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL METRO LINK INCORPORATED BE + * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include +#endif + +#include +#include "os.h" +#include "compiler.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" +#include "Pci.h" + +#include +#include + +/* + * Night Hawk 6400/6408 platform support + */ +#undef NH640X_PCI_MFDEV_SUPPORT +#undef NH640X_PCI_BRIDGE_SUPPORT + +static void nh640xPciInit(void); +static PCITAG nh640xPciFindNext(void); +static PCITAG nh640xPciFindFirst(void); +static CARD32 nh6400PciReadLong(PCITAG tag, int offset); +static void nh6400PciWriteLong(PCITAG tag, int offset, CARD32 val); +static ADDRESS nh6400BusToHostAddr(PCITAG tag, ADDRESS addr); +static ADDRESS nh6400HostToBusAddr(PCITAG tag, ADDRESS addr); +static CARD32 nh6408PciReadLong(PCITAG tag, int offset); +static void nh6408PciWriteLong(PCITAG tag, int offset, CARD32 val); +static ADDRESS nh6408BusToHostAddr(PCITAG tag, ADDRESS addr); +static ADDRESS nh6408HostToBusAddr(PCITAG tag, ADDRESS addr); + +static pciBusFuncs_t nh6400_pci_funcs = { + nh6400PciReadLong, + nh6400PciWriteLong, + nh6400HostToBusAddr, + nh6400BusToHostAddr +}; + +static pciBusFuncs_t nh6408_pci_funcs = { + nh6408PciReadLong, + nh6408PciWriteLong, + nh6408HostToBusAddr, + nh6408BusToHostAddr +}; + +/* + * NH640x CFG address and data register offsets from base + */ +#define NH6400_PCI_CFG_ADDR_REG_OFF 0 +#define NH6400_PCI_CFG_TYPE0_DATA_REG_OFF 0x40 +#define NH6400_PCI_CFG_TYPE1_DATA_REG_OFF 0x80 + +#define NH6408_PCI_CFG_ADDR_REG_OFF 0 +#define NH6408_PCI_CFG_DATA_REG_OFF 0x10000 + +/* + * Possible cfg addr values for NH640x GMEM PMC ports + */ +static unsigned long nh6400_pmc_cfgaddrs[] = { + PCI_CFGMECH1_TYPE0_CFGADDR(0,0,0) +}; + +/* + * Possible cfg addr values for devices on a secondary bus + * (e.g. behind DEC 21152 PCI-to-PCI bridge) + */ +static unsigned long dec_cfgaddrs[] = { + PCI_CFGMECH1_TYPE1_CFGADDR(1,0,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,1,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,2,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,3,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,4,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,5,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,6,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,7,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,8,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,9,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,10,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,11,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,12,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,13,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,14,0,0), + PCI_CFGMECH1_TYPE1_CFGADDR(1,15,0,0) +}; + +/* + * Data structure holding information about various nh640x PCI buses + */ +struct nh640x_pci_info { + int busnum; + int type; + unsigned long num_cfg_addrs; + unsigned long *cfg_addrs; + int primary_bus; + unsigned long cfgPhysBase; + unsigned long memBase; + unsigned long ioBase; + unsigned long ioSize; + unsigned char *cfgAddrReg; /* After mapping */ +}; + +/* Type */ +#define PRIMARY_PCI 0 +#define SECONDARY_PCI 1 + +static struct nh640x_pci_info nh6400_pci_info[] = { +/* pci4 */ { 4, PRIMARY_PCI, 1, nh6400_pmc_cfgaddrs, 0, 0xa0000000, 0xa1000000, 0, 0xa2000000 }, +/* pci12 */ { 12, SECONDARY_PCI, 16, dec_cfgaddrs, 4 }, +#if 0 +/* pci5 */ { 5, PRIMARY_PCI, 1, nh6400_pmc_cfgaddrs, 0, 0xb0000000, 0xb1000000, 0, 0xb2000000 }, +/* pci13 */ { 13, SECONDARY_PCI, 16, dec_cfgaddrs, 5 }, +#endif +}; + +#define NH6400_NUM_PCI_EXPANSION_BUSES (sizeof(nh6400_pci_info)/sizeof(struct nh640x_pci_info)) + +static struct nh640x_pci_info nh6408_pci_info[] = { +/* pci8 */ { 8, PRIMARY_PCI, 1, nh6400_pmc_cfgaddrs, 0, 0x98040000, 0x9a800000, 65536, 0xa0000000 }, +/* pci12 */ { 12, SECONDARY_PCI, 16, dec_cfgaddrs, 8, }, +#if 0 +/* pci9 */ { 9, PRIMARY_PCI, 1, nh6400_pmc_cfgaddrs, 0, 0x99040000, 0x9b800000, 65536, 0xb0000000 }, +/* pci13 */ { 13, SECONDARY_PCI, 16, dec_cfgaddrs, 9, }, +#endif +}; + +#define NH6408_NUM_PCI_EXPANSION_BUSES (sizeof(nh6408_pci_info)/sizeof(struct nh640x_pci_info)) + +extern unsigned long pmax_sys_type; + +#define MOTOPPC_IO_BASE 0x80000000L /* Start of PCI/ISA I/O region */ + +extern void * pmax_iomap(unsigned long, unsigned long); +extern unsigned long ioSize; +extern volatile unsigned char *ioBase; + +void +pmaxPciInit(void) +{ + extern void motoppcPciInit(void); + extern void nh640xPciInit(void); + extern void nh6800tPciInit(void); + + extern unsigned long motoPciMemBase; + extern unsigned long motoPciMemLen; + extern unsigned long motoPciMemBaseCPU; + + /* + * Determine type of machine + */ + switch(pmax_sys_type) { + case MODEL_NH6400: + case MODEL_NH6408: + nh640xPciInit(); + break; + + case MODEL_NH6800T: + nh6800tPciInit(); + break; + + case MODEL_PH620: + case MODEL_PH640: + case MODEL_MMTX: + motoPciMemBase = 0; + motoPciMemLen = 0x20000000; + motoPciMemBaseCPU = 0xa0000000; + /*FALLTHROUGH*/ + + case MODEL_MPWR: + case MODEL_PH610: + case MODEL_MPWR2: + motoppcPciInit(); + break; + + default: + FatalError("pmaxPciInit: Unsupported machine type\n"); + break; + } +} + +void +ppcPciIoMap(int pcibus) +{ + int primary_bus; + + if (ioBase != MAP_FAILED) + munmap((void*)ioBase,ioSize); + + if (!pciBusInfo[pcibus]) + return; + + primary_bus = pciBusInfo[pcibus]->primary_bus; + + if (!pciBusInfo[primary_bus]) + return; + + ioSize = min(pciBusInfo[primary_bus]->ppc_io_size, 64 * 1024); + if (ioSize) { + ioBase = (unsigned char *)pmax_iomap(pciBusInfo[primary_bus]->ppc_io_base, ioSize); + if (ioBase == MAP_FAILED) + ioSize = 0; + } +} + +static void +nh640xPciInit(void) +{ + int i,n; + struct nh640x_pci_info *infop; + pciBusFuncs_p functions; + + switch (pmax_sys_type) { + case MODEL_NH6400: + n = NH6400_NUM_PCI_EXPANSION_BUSES; + infop = nh6400_pci_info; + functions = &nh6400_pci_funcs; + break; + case MODEL_NH6408: + n = NH6408_NUM_PCI_EXPANSION_BUSES; + infop = nh6408_pci_info; + functions = &nh6408_pci_funcs; + break; + default: + FatalError("Unknown Power MAXION system type\n"); + /*NOTREACHED*/ + } + + /* + * Initialize entries in pciBusInfo[] table for each defined PCI bus. + * This table is actually sparse because undefined or inaccessible + * pci buses are left as NULL entries. Of course, pciFindNext() is + * aware of this convention, and will skip the undefined buses. + */ + for (i=0; ibusnum; + pciBusInfo_t *busp; + + if (pciBusInfo[bus]) + busp = pciBusInfo[bus]; + else + busp = xalloc(sizeof(pciBusInfo_t)); + + if (!busp) + FatalError("nh640xPciInit: xalloc failed\n"); + + /* Initialize pci bus info */ + busp->configMech = PCI_CFG_MECH_OTHER; + busp->numDevices = infop->num_cfg_addrs; + busp->secondary = (infop->type == SECONDARY_PCI ? TRUE : FALSE); + busp->primary_bus = infop->primary_bus; + busp->funcs = functions; + busp->pciBusPriv = infop; + + /* Initialize I/O base/size info */ + if (busp->secondary) { + pciBusInfo_t *pri_busp = pciBusInfo[busp->primary_bus]; + if (pri_busp) { + busp->ppc_io_base = pri_busp->ppc_io_base; + busp->ppc_io_size = pri_busp->ppc_io_size; + } + } + else if (infop->ioSize) { + busp->ppc_io_size = infop->ioSize; + busp->ppc_io_base = infop->ioBase; + } + + pciBusInfo[bus] = busp; + + /* + * Adjust pciNumBuses to reflect the highest defined entry in pciBusInfo + */ + if (pciNumBuses < bus) + pciNumBuses = bus + 1; + } + + pciFindFirstFP = nh640xPciFindFirst; + pciFindNextFP = nh640xPciFindNext; +} + +static PCITAG +nh640xPciFindNext(void) +{ + unsigned long devid, tmp; + unsigned char base_class, sub_class, sec_bus, pri_bus; + + for (;;) { + + if (pciBusNum == -1) { + /* + * Start at top of the order + */ + pciBusNum = 0; + pciFuncNum = 0; + pciDevNum = 0; + } + else { +#ifdef NH640X_PCI_MFDEV_SUPPORT + /* + * Somewhere in middle of order. Determine who's + * next up + */ + if (pciFuncNum == 0) { + /* + * Is current dev a multifunction device? + */ + if (pciMfDev(pciBusNum, pciDevNum)) + /* Probe for other functions */ + pciFuncNum = 1; + else + /* No more functions this device. Next device please */ + pciDevNum ++; + } + else if (++pciFuncNum >= 8) { + /* No more functions for this device. Next device please */ + pciFuncNum = 0; + pciDevNum ++; + } +#else /* NH640X_PCI_MFDEV_SUPPORT */ + pciDevNum++; +#endif /* NH640X_PCI_MFDEV_SUPPORT */ + + if (!pciBusInfo[pciBusNum] || pciDevNum >= pciBusInfo[pciBusNum]->numDevices) { + /* + * No more devices for this bus. Next bus please + */ + if (++pciBusNum >= pciNumBuses) + /* No more buses. All done for now */ + return(PCI_NOT_FOUND); + + pciDevNum = 0; + } + } + + if (!pciBusInfo[pciBusNum]) + continue; /* Undefined bus, next bus/device please */ + + /* + * At this point, pciBusNum, pciDevNum, and pciFuncNum have been + * advanced to the next device. Compute the tag, and read the + * device/vendor ID field. + */ + pciDeviceTag = PCI_MAKE_TAG(pciBusNum, pciDevNum, pciFuncNum); + devid = pciReadLong(pciDeviceTag, 0); + if (devid == 0xffffffff) + continue; /* Nobody home. Next device please */ + +#ifdef NH640X_PCI_BRIDGE_SUPPORT + /* + * Before checking for a specific devid, look for enabled + * PCI to PCI bridge devices. If one is found, create and + * initialize a bus info record (if one does not already exist). + */ + tmp = pciReadLong(pciDeviceTag, PCI_CLASS_CODE_REG); + base_class = PCI_EXTRACT_BASE_CLASS(tmp); + sub_class = PCI_EXTRACT_SUBCLASS(tmp); + if (base_class == PCI_CLASS_BRIDGE && sub_class == PCI_SUBCLASS_BRIDGE_PCI) { + tmp = pciReadLong(pciDeviceTag, PCI_BRIDGE_BUS_REG); + sec_bus = PCI_SECONDARY_BUS_EXTRACT(tmp); + pri_bus = PCI_PRIMARY_BUS_EXTRACT(tmp); + if (sec_bus > 0 && sec_bus < PCI_MAX_BUSES && pcibusInfo[pri_bus]) { + /* + * Found a secondary PCI bus + */ + if (!pciBusInfo[sec_bus]) { + pciBusInfo[sec_bus] = xalloc(sizeof(pciBusInfo_t)); + + if (!pciBusInfo[sec_bus]) + FatalError("nh640xPciFindNext: alloc failed\n!!!"); + } + + /* Copy parents settings... */ + *pciBusInfo[sec_bus] = *pcibusInfo[pri_bus]; + + /* ...but not everything same as parent */ + pciBusInfo[sec_bus]->primary_bus = pri_bus; + pciBusInfo[sec_bus]->secondary = TRUE; + pciBusInfo[sec_bus]->numDevices = 32; + + if (pciNumBuses < sec_num) + pciNumBuses = sec_num+1; + } + } +#endif /* NH640X_PCI_BRIDGE_SUPPORT */ + + /* + * Does this device match the requested devid after + * applying mask? + */ + if ((devid & pciDevidMask) == pciDevid) { + /* Yes - Return it. Otherwise, next device */ + + /* However, before returning it, try to map */ + /* I/O region for this PCI bus */ + ppcPciIoMap(PCI_BUS_FROM_TAG(pciDeviceTag)); + + return(pciDeviceTag); /* got a match */ + } + + } /* for */ + + /*NOTREACHED*/ +} + +static PCITAG +nh640xPciFindFirst(void) +{ + pciBusNum = -1; + return(nh640xPciFindNext()); +} + +static unsigned long +nh6400PciReadLong(PCITAG tag, int offset) +{ + unsigned long tmp; + char *base; + int devnum, bus, func, data_reg_offset, ndevs; + unsigned long cfgaddr; + pciBusInfo_t *busp, *pri_busp; + struct nh640x_pci_info *infop, *pri_infop; + + bus = PCI_BUS_FROM_TAG(tag); + devnum = PCI_DEV_FROM_TAG(tag); + func = PCI_FUNC_FROM_TAG(tag); + + xf86MsgVerb(3, X_INFO, + "nh6400PciReadLong: bus=%d, devnum=%d, func=%d, offset=0x%x\n", + bus, devnum, func, offset); + + if (bus >= pciNumBuses || !pciBusInfo[bus]) { + xf86Msg(X_WARNING, "nh6400PciReadLong: bus pci%d not defined!!!\n", + bus); + return(0xffffffff); + } + + busp = pciBusInfo[bus]; + infop = (struct nh640x_pci_info *)busp->pciBusPriv; + + if (busp->secondary) { + /* + * Secondary PCI bus behind a pci-to-pci bridge + */ + pri_busp = pciBusInfo[busp->primary_bus]; + pri_infop = (struct nh640x_pci_info *)pri_busp->pciBusPriv; + ndevs = 16; + data_reg_offset = NH6400_PCI_CFG_TYPE1_DATA_REG_OFF; /* For Type 1 cfg cycles */ + + if (!pri_busp) { + xf86Msg(X_WARNING, + "nh6400PciReadLong: pci%d's primary parent [pci%d] " + "is not defined!!!\n", bus, busp->primary_bus); + return(0xffffffff); + } + } + else { + pri_busp = busp; + pri_infop = infop; + ndevs = infop->num_cfg_addrs; + data_reg_offset = NH6400_PCI_CFG_TYPE0_DATA_REG_OFF; /* For Type 0 cfg cycles */ + } + + if (devnum >= ndevs) { + xf86Msg(X_WARNING, + "nh6400PciReadLong: devnum %d out of range for bus pci%d\n", + devnum, bus); + return(0xffffffff); + } + + /* + * Make sure the cfg address and data registers for this bus are mapped + * Secondary buses just use the primary parents addreses + */ + if (!infop->cfgAddrReg) { + if (!pri_infop->cfgAddrReg) { + pri_infop->cfgAddrReg = pmax_iomap(pri_infop->cfgPhysBase, 0x1000); + if (pri_infop->cfgAddrReg == MAP_FAILED) { + FatalError("nh6400PciReadLong: Cannot map PCI cfg regs @ 0x%08x\n", + pri_infop->cfgPhysBase); + /*NOTREACHED*/ + } + } + infop->cfgAddrReg = pri_infop->cfgAddrReg; + infop->cfgPhysBase = pri_infop->cfgPhysBase; + } + base = infop->cfgAddrReg; + + if (busp->secondary) { + /* cfgaddr = PCI_CFGMECH1_TYPE1_CFGADDR(bus,devnum,func,offset); */ + cfgaddr = PCI_CFGMECH1_TYPE1_CFGADDR(1,devnum,func,offset); /* Must use bus=1 for now - glb */ + } + else { + cfgaddr = infop->cfg_addrs[devnum] + offset; + } + + xf86MsgVerb(X_INFO, 3, + "nh6400PciReadLong: Writing cfgaddr=0x%x to 0x%x (phys=0x%x)\n", + cfgaddr, base, infop->cfgPhysBase); + + /* There may not be any OS interaction while interrupts are disabled */ + xf86DisableInterrupts(); + + *((unsigned long *)(base)) = pciByteSwap(cfgaddr); /* Set cfg address */ + eieio(); + + if (!badaddr(base + data_reg_offset, 4, 0)) { + tmp = *((unsigned long *)(base + data_reg_offset)); + eieio(); + } + + xf86EnableInterrupts(); + + xf86MsgVerb(X_INFO, 3, "nh6400PciReadLong: Read value=0x%x from 0x%x (phys=0x%x)\n", + pciByteSwap(tmp), base + data_reg_offset, infop->cfgPhysBase + data_reg_offset); + + return(pciByteSwap(tmp)); +} + +static void +nh6400PciWriteLong(PCITAG tag, int offset, unsigned long val) +{ + char *base; + int devnum, bus, func, data_reg_offset, ndevs; + unsigned long cfgaddr; + pciBusInfo_t *busp, *pri_busp; + struct nh640x_pci_info *infop, *pri_infop; + + bus = PCI_BUS_FROM_TAG(tag); + devnum = PCI_DEV_FROM_TAG(tag); + func = PCI_FUNC_FROM_TAG(tag); + + xf86MsgVerb(X_INFO, 3, + "nh6400PciWriteLong: bus=%d, devnum=%d, func=%d, offset=0x%x, " + val=0x%x\n", bus, devnum, func, offset, val); + + if (bus >= pciNumBuses || !pciBusInfo[bus]) { + xf86Msg(X_WARNING, "nh6400PciWriteLong: bus pci%d not defined!!!\n", + bus); + return; + } + busp = pciBusInfo[bus]; + infop = (struct nh640x_pci_info *)busp->pciBusPriv; + + if (busp->secondary) { + /* + * Secondary PCI bus behind a pci-to-pci bridge + */ + pri_busp = pciBusInfo[busp->primary_bus]; + pri_infop = (struct nh640x_pci_info *)pri_busp->pciBusPriv; + ndevs = 16; + data_reg_offset = NH6400_PCI_CFG_TYPE1_DATA_REG_OFF; /* For Type 1 cfg cycles */ + + if (!pri_busp) { + xf86Msg(X_WARNING, + "nh6400PciWriteLong: pci%d's primary parent [pci%d]" + " is not defined!!!\n", bus, busp->primary_bus); + return; + } + } + else { + pri_busp = busp; + pri_infop = infop; + ndevs = infop->num_cfg_addrs; + data_reg_offset = NH6400_PCI_CFG_TYPE0_DATA_REG_OFF; /* For Type 0 cfg cycles */ + } + + if (devnum >= ndevs) { + xf86Msg(X_WARNING, + "nh6400PciWriteLong: devnum %d out of range for bus pci%d\n", + devnum, bus); + return; + } + + /* + * Make sure the cfg address and data registers for this bus are mapped + * Secondary buses just use the primary parents addreses + */ + if (!infop->cfgAddrReg) { + if (!pri_infop->cfgAddrReg) { + pri_infop->cfgAddrReg = pmax_iomap(pri_infop->cfgPhysBase, 0x1000); + if (pri_infop->cfgAddrReg == MAP_FAILED) { + FatalError("nh6400PciWriteLong: Cannot map PCI cfg regs @ 0x%08x\n", + pri_infop->cfgPhysBase); + /*NOTREACHED*/ + } + } + infop->cfgAddrReg = pri_infop->cfgAddrReg; + infop->cfgPhysBase = pri_infop->cfgPhysBase; + } + base = infop->cfgAddrReg; + + if (busp->secondary) { + /* cfgaddr = PCI_CFGMECH1_TYPE1_CFGADDR(bus,devnum,func,offset); */ + cfgaddr = PCI_CFGMECH1_TYPE1_CFGADDR(1,devnum,func,offset); /* Must use bus=1 for now - glb */ + } + else { + cfgaddr = infop->cfg_addrs[devnum] + offset; + } + + xf86MsgVerb(X_INFO, 3, + "nh6400PciWriteLong: Writing cfgaddr=0x%x to 0x%x (phys=0x%x)\n", + cfgaddr, base, infop->cfgPhysBase); + + /* There may not be any OS interaction while interrupts are disabled */ + xf86DisableInterrupts(); + + *((unsigned long *)(base)) = pciByteSwap(cfgaddr); /* Set cfg address */ + eieio(); + + *((unsigned long *)(base + data_reg_offset)) = pciByteSwap(val); + eieio(); + + xf86EnableInterrupts(); + + xf86MsgVerb(X_INFO, 3, + "nh6400PciWriteLong: Wrote value=0x%x to 0x%x (phys=0x%x)\n", + val, base + data_reg_offset, + infop->cfgPhysBase + data_reg_offset); +} + +/* + * These next two functions are for debugging purposes only because + * the nh6400 does not translate passed to/from a PCI domain. However, + * we do do some bounds checking to make sure things are where they + * should be. + */ +static ADDRESS +nh6400BusToHostAddr(PCITAG tag, ADDRESS addr) +{ + unsigned long addr_l = (unsigned long)addr; + int bus = PCI_BUS_FROM_TAG(tag); + struct nh640x_pci_info *infop; + int pri_bus; + unsigned long membase; + + if (!pciBusInfo[bus]) + FatalError("nh6400BusToHostAddr: pci%d not defined!!\n", bus); + + if (pciBusInfo[bus]->secondary) { + pri_bus = pciBusInfo[bus]->primary_bus; + + if (!pciBusInfo[pri_bus]) + FatalError("nh6400BusToHostAddr: Primary bus pci%d not defined!!\n", pri_bus); + } + else + pri_bus = bus; + + infop = (struct nh640x_pci_info *)pciBusInfo[pri_bus]->pciBusPriv; + membase = infop->memBase; + + if (addr_l < 0x80000000) + /* + * NH6400 host memory addresses are 0-0x7fffffff + */ + return(addr); + + else if (addr_l >= membase && addr_l < membase + 0x0e000000) + /* + * NH6400 host can access PCI memory space addresses + * [memBase, memBase+0x0dffffff] + */ + return(addr); + else + /* Other addresses are not valid */ + FatalError("nh6400BusToHostAddr: Bus address 0x%x not visible to NH6400 host\n", + addr_l); + + /*NOTREACHED*/ +} + +static ADDRESS +nh6400HostToBusAddr(PCITAG tag, ADDRESS addr) +{ + unsigned long addr_l = (unsigned long) addr; + int bus = PCI_BUS_FROM_TAG(tag); + struct nh640x_pci_info *infop; + int pri_bus; + unsigned long membase; + + if (!pciBusInfo[bus]) + FatalError("nh6400HostToBusAddr: pci%d not defined!!\n", bus); + + if (pciBusInfo[bus]->secondary) { + pri_bus = pciBusInfo[bus]->primary_bus; + + if (!pciBusInfo[pri_bus]) + FatalError("nh6400HostToBusAddr: Primary bus pci%d not defined!!\n", pri_bus); + } + else + pri_bus = bus; + + infop = (struct nh640x_pci_info *)pciBusInfo[pri_bus]->pciBusPriv; + membase = infop->memBase; + + if (addr_l < 0x80000000) + /* + * NH6400 host memory addresses are 0-0x7fffffff + */ + return(addr); + + else if (addr_l >= membase && addr_l < membase + 0x0e000000) + /* + * NH6400 host can access PCI memory space addresses + * [memBase, memBase+0x0dffffff] + */ + return(addr); + else + /* Other addresses are not valid */ + FatalError("nh6400HostToBusAddr: Bus address 0x%x not visible to NH6400 host\n", + addr_l); + + /*NOTREACHED*/ +} + + +/* + * NH6408 platform support + */ +static unsigned long +nh6408PciReadLong(PCITAG tag, int offset) +{ + unsigned long tmp; + char *base; + int devnum, bus, func, ndevs; + unsigned long cfgaddr; + pciBusInfo_t *busp, *pri_busp; + struct nh640x_pci_info *infop, *pri_infop; + + bus = PCI_BUS_FROM_TAG(tag); + devnum = PCI_DEV_FROM_TAG(tag); + func = PCI_FUNC_FROM_TAG(tag); + + xf86MsgVerb(X_INFO, + "nh6408PciReadLong: bus=%d, devnum=%d, func=%d, offset=0x%x\n", + bus, devnum, func, offset); + + if (bus >= pciNumBuses || !pciBusInfo[bus]) { + xf86Msg(X_WARNING, "nh6408PciReadLong: bus pci%d not defined!!!\n", + bus); + return(0xffffffff); + } + + busp = pciBusInfo[bus]; + infop = (struct nh640x_pci_info *)busp->pciBusPriv; + + if (busp->secondary) { + /* + * Secondary PCI bus behind a pci-to-pci bridge + */ + pri_busp = pciBusInfo[busp->primary_bus]; + pri_infop = (struct nh640x_pci_info *)pri_busp->pciBusPriv; + ndevs = 16; + + if (!pri_busp) { + xf86Msg(X_WARNING, + "nh6408PciReadLong: pci%d's primary parent [pci%d] " + "is not defined!!!\n", bus, busp->primary_bus); + return(0xffffffff); + } + } + else { + pri_busp = busp; + pri_infop = infop; + ndevs = infop->num_cfg_addrs; + } + + if (devnum >= ndevs) { + xf86Msg(X_WARNING + "nh6408PciReadLong: devnum %d out of range for bus pci%d\n", + devnum, bus); + return(0xffffffff); + } + + /* + * Make sure the cfg address and data registers for this bus are mapped + * Secondary buses just use the primary parents addreses + */ + if (!infop->cfgAddrReg) { + if (!pri_infop->cfgAddrReg) { + pri_infop->cfgAddrReg = pmax_iomap(pri_infop->cfgPhysBase, 0x11000); + if (pri_infop->cfgAddrReg == MAP_FAILED) { + FatalError("nh6408PciReadLong: Cannot map PCI cfg regs @ 0x%08x\n", + pri_infop->cfgPhysBase); + /*NOTREACHED*/ + } + } + infop->cfgAddrReg = pri_infop->cfgAddrReg; + infop->cfgPhysBase = pri_infop->cfgPhysBase; + } + base = infop->cfgAddrReg; + + if (busp->secondary) { + /* cfgaddr = PCI_CFGMECH1_TYPE1_CFGADDR(bus,devnum,func,offset); */ + cfgaddr = PCI_CFGMECH1_TYPE1_CFGADDR(1,devnum,func,offset); /* Must use bus=1 for now - glb */ + } + else { + cfgaddr = infop->cfg_addrs[devnum] + offset; + } + + xf86MsgVerb(X_INFO, 3, + "nh6408PciReadLong: Writing cfgaddr=0x%x to 0x%x (phys=0x%x)\n", + cfgaddr, base, infop->cfgPhysBase); + + /* There may not be any OS interaction while interrupts are disabled */ + xf86DisableInterrupts(); + + *((unsigned long *)(base)) = pciByteSwap(cfgaddr); /* Set cfg address */ + eieio(); + + if (!badaddr(base + NH6408_PCI_CFG_DATA_REG_OFF, 4, 0)) { + tmp = *((unsigned long *)(base + NH6408_PCI_CFG_DATA_REG_OFF)); + eieio(); + } + + xf86EnableInterrupts(); + + xf86MsgVerb(X_INFO, 3, "nh6408PciReadLong: Read value=0x%x from 0x%x (phys=0x%x)\n", + pciByteSwap(tmp), + base + NH6408_PCI_CFG_DATA_REG_OFF, + infop->cfgPhysBase + NH6408_PCI_CFG_DATA_REG_OFF); + + return(pciByteSwap(tmp)); +} + +static void +nh6408PciWriteLong(PCITAG tag, int offset, unsigned long val) +{ + char *base; + int devnum, bus, func, ndevs; + unsigned long cfgaddr; + pciBusInfo_t *busp, *pri_busp; + struct nh640x_pci_info *infop, *pri_infop; + + bus = PCI_BUS_FROM_TAG(tag); + devnum = PCI_DEV_FROM_TAG(tag); + func = PCI_FUNC_FROM_TAG(tag); + + xf86MsgVerb(X_INFO, + "nh6408PciWriteLong: bus=%d, devnum=%d, func=%d, offset=0x%x, " + "val=0x%x\n", bus, devnum, func, offset, val); + + if (bus >= pciNumBuses || !pciBusInfo[bus]) { + xf86Msg(X_WARNING, "nh6408PciWriteLong: bus pci%d not defined!!!\n", + bus); + return; + } + + busp = pciBusInfo[bus]; + infop = (struct nh640x_pci_info *)busp->pciBusPriv; + + if (busp->secondary) { + /* + * Secondary PCI bus behind a pci-to-pci bridge + */ + pri_busp = pciBusInfo[busp->primary_bus]; + pri_infop = (struct nh640x_pci_info *)pri_busp->pciBusPriv; + ndevs = 16; + + if (!pri_busp) { + xf86Msg(X_WARNING, + "nh6408PciWriteLong: pci%d's primary parent [pci%d] " + is not defined!!!\n", bus, busp->primary_bus); + return; + } + } + else { + pri_busp = busp; + pri_infop = infop; + ndevs = infop->num_cfg_addrs; + } + + if (devnum >= ndevs) { + xf86Msg(X_WARNING, + "nh6408PciWriteLong: devnum %d out of range for bus pci%d\n", + devnum, bus); + return; + } + + /* + * Make sure the cfg address and data registers for this bus are mapped + * Secondary buses just use the primary parents addreses + */ + if (!infop->cfgAddrReg) { + if (!pri_infop->cfgAddrReg) { + pri_infop->cfgAddrReg = pmax_iomap(pri_infop->cfgPhysBase, 0x11000); + if (pri_infop->cfgAddrReg == MAP_FAILED) { + FatalError("nh6408PciWriteLong: Cannot map PCI cfg regs @ 0x%08x\n", + pri_infop->cfgPhysBase); + /*NOTREACHED*/ + } + } + infop->cfgAddrReg = pri_infop->cfgAddrReg; + infop->cfgPhysBase = pri_infop->cfgPhysBase; + } + base = infop->cfgAddrReg; + + if (busp->secondary) { + /* cfgaddr = PCI_CFGMECH1_TYPE1_CFGADDR(bus,devnum,0,offset); */ + cfgaddr = PCI_CFGMECH1_TYPE1_CFGADDR(1,devnum,0,offset); + } + else { + cfgaddr = infop->cfg_addrs[devnum] + offset; + } + + xf86MsgVerb(X_INFO, 3, + "nh6408PciWriteLong: Writing cfgaddr=0x%x to 0x%x (phys=0x%x)\n", + cfgaddr, base, infop->cfgPhysBase); + + /* There may not be any OS interaction while interrupts are disabled */ + xf86DisableInterrupts(); + + *((unsigned long *)(base)) = pciByteSwap(cfgaddr); /* Set cfg address */ + eieio(); + + *((unsigned long *)(base + NH6408_PCI_CFG_DATA_REG_OFF)) = pciByteSwap(val); + eieio(); + + xf86EnableInterrupts(); + + xf86MsgVerb(X_INFO, 3, + "nh6408PciWriteLong: Wrote value=0x%x to 0x%x (phys=0x%x)\n", + val, base + NH6408_PCI_CFG_DATA_REG_OFF, + infop->cfgPhysBase + NH6408_PCI_CFG_DATA_REG_OFF); +} + + +static ADDRESS +nh6408BusToHostAddr(PCITAG tag, ADDRESS addr) +{ + unsigned long addr_l = (unsigned long)addr; + int bus = PCI_BUS_FROM_TAG(tag); + int pri_bus; + struct nh640x_pci_info *infop; + unsigned long membase; + + if (!pciBusInfo[bus]) + FatalError("nh6408BusToHostAddr: pci%d not defined!!\n", bus); + + if (pciBusInfo[bus]->secondary) { + pri_bus = pciBusInfo[bus]->primary_bus; + + if (!pciBusInfo[pri_bus]) + FatalError("nh6408BusToHostAddr: Primary bus pci%d not defined!!\n", pri_bus); + } + else + pri_bus = bus; + + infop = (struct nh640x_pci_info *)pciBusInfo[pri_bus]->pciBusPriv; + membase = infop->memBase; + + if (addr_l < 0x10000000) + /* + * NH6408 host sees PCI memory space addresses 0-0x0fffffff + * at the primary PCI buses "memBase" [memBase, memBase+0x0fffffff] + */ + return((ADDRESS)(membase + addr_l)); + + else if (addr_l >= 0x80000000) + /* + * NH6408 host memory addresses 0-0x7fffffff are seen at + * 0x80000000-0xffffffff on PCI + */ + return((ADDRESS)(addr_l & 0x7fffffff)); + + else + /* Other addresses are not valid */ + FatalError("nh6408BusToHostAddr: Bus address 0x%x not visible to NH6408 host\n", + addr_l); + + /*NOTREACHED*/ +} + +static ADDRESS +nh6408HostToBusAddr(PCITAG tag, ADDRESS addr) +{ + unsigned long addr_l = (unsigned long)addr; + int bus = PCI_BUS_FROM_TAG(tag); + int pri_bus; + struct nh640x_pci_info *infop; + unsigned long membase; + + if (!pciBusInfo[bus]) + FatalError("nh6408HostToBusAddr: pci%d not defined!!\n", bus); + + if (pciBusInfo[bus]->secondary) { + pri_bus = pciBusInfo[bus]->primary_bus; + + if (!pciBusInfo[pri_bus]) + FatalError("nh6408HostToBusAddr: Primary bus pci%d not defined!!\n", pri_bus); + } + else + pri_bus = bus; + + infop = (struct nh640x_pci_info *)pciBusInfo[pri_bus]->pciBusPriv; + membase = infop->memBase; + + if (addr_l < 0x80000000) + /* + * NH6408 host memory addresses 0-0x7fffffff are seen at + * 0x80000000-0xffffffff on PCI + */ + return((ADDRESS)(addr_l | 0x80000000)); + + else if (addr_l >= membase && addr_l < (membase + 0x10000000)) + /* + * NH6408 host sees PCI memory space addresses 0-0x0fffffff + * at the primary PCI buses "memBase" [memBase, memBase+0x0fffffff] + */ + return((ADDRESS)(addr_l - membase)); + + else + /* Other addresses are not valid */ + FatalError("nh6408HostToBusAddr: Host address 0x%x not visible to pci%d\n", + addr_l, bus); + + /*NOTREACHED*/ +} + +/* + * NH6800 (Turbo) support + */ +static void +nh6800tPciInit(void) +{ + FatalError("nh6800tPciInit: NH6800TURBO not supported (yet)!!!\n"); +} -- cgit v1.2.3