1994-09-01 03:45:19 +02:00
|
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** $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[] =
|
1994-09-16 02:33:29 +02:00
|
|
|
|
"\n$Id: pcibios.c,v 2.0.0.2 94/08/18 23:04:11 wolf Exp $\n";
|
1994-09-01 03:45:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** 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);
|
|
|
|
|
}
|