freebsd-skq/sys/i386/pci/pcibios.c
se 2c2543e63e Submitted by: Wolfgang Stanglmeier <wolf@dentaro.GUN.de> + Stefan Esser <se>
Directory for PCI autoconfigure and device driver code.
1994-09-01 01:45:19 +00:00

317 lines
7.6 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**************************************************************************
**
** $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.
**
**-------------------------------------------------------------------------
**
** $Log: pcibios.c,v $
** Revision 2.0.0.2 94/08/18 23:04:11 wolf
** Copyright message.
** New function pci_last_bus().
**
** Revision 2.0.0.1 94/08/01 20:35:29 wolf
** Option: PCI_CONF_MODE to disable pci autodetect code.
** Flipped code for mode1 and mode2.
**
** Revision 2.0 94/07/10 15:53:31 wolf
** FreeBSD release.
**
** Revision 1.0 94/06/07 20:02:20 wolf
** Beta release.
**
***************************************************************************
*/
#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"
"Copyright (c) 1994, Wolfgang Stanglmeier\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);
}