/************************************************************************** ** ** $Id: pcibios.c,v 2.0.0.2 94/08/18 23:04:11 wolf Exp $ ** ** #define for pci-bus bios functions. ** ** 386bsd / FreeBSD ** **------------------------------------------------------------------------- ** ** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions ** are met: ** 1. Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** **------------------------------------------------------------------------- */ #include "types.h" #include "i386/isa/isa.h" #include "i386/pci/pci.h" #include "i386/pci/pcibios.h" extern int printf(); static char pci_mode; char ident_pcibios_c[] = "\n$Id: pcibios.c,v 2.0.0.2 94/08/18 23:04:11 wolf Exp $\n"; /*-------------------------------------------------------------------- ** ** Port access ** **-------------------------------------------------------------------- ** ** @FREEBSD@ inl() and outl() functions are not defined */ #define DIRTY #ifdef DIRTY #undef inl #define inl(port) \ ({ u_long data; \ __asm __volatile("inl %1, %0": "=a" (data): "d" ((u_short)(port))); \ data; }) #undef outl #define outl(port, data) \ {__asm __volatile("outl %0, %1"::"a" ((u_long)(data)), "d" ((u_short)(port)));} #undef inb #define inb(port) \ ({ u_char data; \ __asm __volatile("inb %1, %0": "=a" (data): "d" ((u_short)(port))); \ data; }) #undef outb #define outb(port, data) \ {__asm __volatile("outb %0, %1"::"a" ((u_char)(data)), "d" ((u_short)(port)));} #endif /*-------------------------------------------------------------------- ** ** Determine configuration mode ** **-------------------------------------------------------------------- */ #define CONF1_ENABLE 0x80000000ul #define CONF1_ADDR_PORT 0x0cf8 #define CONF1_DATA_PORT 0x0cfc #define CONF2_ENABLE_PORT 0x0cf8 #define CONF2_FORWARD_PORT 0x0cfa int pci_conf_mode (void) { #ifdef PCI_CONF_MODE return (PCI_CONF_MODE) #else /* PCI_CONF_MODE */ u_long result, oldval; /*--------------------------------------- ** Configuration mode 2 ? **--------------------------------------- */ outb (CONF2_ENABLE_PORT, 0); outb (CONF2_FORWARD_PORT, 0); if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) { pci_mode = 2; return (2); }; /*--------------------------------------- ** Configuration mode 1 ? **--------------------------------------- */ oldval = inl (CONF1_ADDR_PORT); outl (CONF1_ADDR_PORT, CONF1_ENABLE); result = inl (CONF1_ADDR_PORT); outl (CONF1_ADDR_PORT, oldval); if (result == CONF1_ENABLE) { pci_mode = 1; return (1); }; /*--------------------------------------- ** No PCI bus available. **--------------------------------------- */ return (0); #endif /* PCI_CONF_MODE */ } /*-------------------------------------------------------------------- ** ** Build a pcitag from bus, device and function number ** **-------------------------------------------------------------------- */ pcici_t pcitag (unsigned char bus, unsigned char device, unsigned char func) { pcici_t tag; tag.cfg1 = 0; if (device >= 32) return tag; if (func >= 8) return tag; switch (pci_mode) { case 1: tag.cfg1 = CONF1_ENABLE | (((u_long) bus ) << 16ul) | (((u_long) device) << 11ul) | (((u_long) func ) << 8ul); break; case 2: if (device >= 16) break; tag.cfg2.port = 0xc000 | (device << 8ul); tag.cfg2.enable = 0xf1 | (func << 1ul); tag.cfg2.forward = bus; break; }; return tag; } /*-------------------------------------------------------------------- ** ** Read register from configuration space. ** **-------------------------------------------------------------------- */ u_long pci_conf_read (pcici_t tag, u_long reg) { u_long addr, data = 0; if (!tag.cfg1) return (0xfffffffful); switch (pci_mode) { case 1: addr = tag.cfg1 | reg & 0xfc; #ifdef PCI_DEBUG printf ("pci_conf_read(1): addr=%x ", addr); #endif outl (CONF1_ADDR_PORT, addr); data = inl (CONF1_DATA_PORT); outl (CONF1_ADDR_PORT, 0 ); break; case 2: addr = tag.cfg2.port | reg & 0xfc; #ifdef PCI_DEBUG printf ("pci_conf_read(2): addr=%x ", addr); #endif outb (CONF2_ENABLE_PORT , tag.cfg2.enable ); outb (CONF2_FORWARD_PORT, tag.cfg2.forward); data = inl ((u_short) addr); outb (CONF2_ENABLE_PORT, 0); outb (CONF2_FORWARD_PORT, 0); break; }; #ifdef PCI_DEBUG printf ("data=%x\n", data); #endif return (data); } /*-------------------------------------------------------------------- ** ** Write register into configuration space. ** **-------------------------------------------------------------------- */ void pci_conf_write (pcici_t tag, u_long reg, u_long data) { u_long addr; if (!tag.cfg1) return; switch (pci_mode) { case 1: addr = tag.cfg1 | reg & 0xfc; #ifdef PCI_DEBUG printf ("pci_conf_write(1): addr=%x data=%x\n", addr, data); #endif outl (CONF1_ADDR_PORT, addr); outl (CONF1_DATA_PORT, data); outl (CONF1_ADDR_PORT, 0 ); break; case 2: addr = tag.cfg2.port | reg & 0xfc; #ifdef PCI_DEBUG printf ("pci_conf_write(2): addr=%x data=%x\n", addr, data); #endif outb (CONF2_ENABLE_PORT, tag.cfg2.enable); outb (CONF2_FORWARD_PORT, tag.cfg2.forward); outl ((u_short) addr, data); outb (CONF2_ENABLE_PORT, 0); outb (CONF2_FORWARD_PORT, 0); break; }; } /*-------------------------------------------------------------------- ** ** Get the number of available PCI busses. ** **-------------------------------------------------------------------- */ /* ** A certain chipset seems to ignore the bus number. ** Until fixed, check only bus 0. ** Maybe it's a good idea to ask the real pci bios ** if available. */ #ifndef PCI_LAST_BUS #define PCI_LAST_BUS (0) #endif /* PCI_LAST_BUS */ int pci_last_bus (void) { return (PCI_LAST_BUS); }