/*
* $Id$
*/
/*
* Copyright (c) 2002 Johnny Zackrisson. All rights reserved.
*
* You are free to do whatever you want with this code.
*/
#include <drivers/pci_pio.h>
#include <config.h>
#ifdef _PCI_SUPPORT_
/*
* Fill in your shit, recompile and prey.
*/
#define PCI_DEVS /* how many devices */
struct pci_device_id_t pci_devices = {
/* Vendor id, device id, name */
0x0000,0x0000,"Oak Technologies" /* example */
};
#endif /* PCI_DEVS */
/* XXX: these does not belong here */
static void outb(u16 port, u8 data);
static void outw(u16 port, u16 data);
static void outl(u16 port, u32 data);
static u8 inb(u16 port);
static u16 inw(u16 port);
static u32 inl(u16 port);
/*
* XXX: static?
*/
int pci_get_type();
int pci_init();
int pci_find_devices(struct pci_conf_t *pci_conf[]);
int pci_t1_read_config(struct pci_conf_t *pci_conf, unsigned int dev);
int pci_t1_write_config(struct pci_conf_t *pci_conf, unsigned int dev);
int pci_t2_read_config(struct pci_conf_t *pci_conf, unsigned int dev);
int pci_t2_write_config(struct pci_conf_t *pci_conf, unsigned int dev);
int
pci_init()
{
return(0);
}
int
pci_get_type()
{
int x,t=0;
outb(PCI_BASE, 0);
outb(PCI_INDEX_REG, 0);
x = inb(PCI_BASE) + inb(PCI_INDEX_REG);
if (x == 0)
t = PCI_TYPE_2;
x = inb(PCI_BASE);
outl(PCI_BASE, BUS_ADDRESS);
x = inl(PCI_BASE);
if (x == BUS_ADDRESS)
t = PCI_TYPE_1;
outl(PCI_BASE, x);
return(t);
}
int
pci_find_devices(struct pci_conf_t *pci_conf[])
{
int dev,i,x;
x = pci_get_type();
if (x == PCI_TYPE_1) {
for (i=0; i<PCI_DEVS; i++) {
pci_t1_read_config(pci_conf[dev], i);
if (pci_conf[dev]->vendor_id != 0xffff &&
pci_conf[dev]->device_id != 0xffff)
dev++;
}
return(0);
} else if (x == PCI_TYPE_2) {
for (i=0; i<PCI_DEVS; i++) {
pci_t2_read_config(pci_conf[dev], i);
if (pci_conf[dev]->vendor_id != 0xffff &&
pci_conf[dev]->device_id != 0xffff)
dev++;
}
return(0);
}
return(-1);
}
/* PCI type 1 access method */
int
pci_t1_read_config(struct pci_conf_t *pci_conf, unsigned int dev)
{
unsigned int i;
dev <<= 11;
for (i=0; i<64; i++) {
outl(PCI_BASE, (BUS_ADDRESS+(dev+(i*4))));
((u32 *)pci_conf)[i] = inl(PCI_T1_INDEX_REG);
}
if ((pci_conf->vendor_id == 0xffff) &&
(pci_conf->device_id == 0xffff))
return(-1);
return(0);
}
int
pci_t1_write_config(struct pci_conf_t *pci_conf, unsigned int dev)
{
int i;
/* bit 0-7 index into the conf space */
dev <<= 11;
for (i=0; i<64; i++) {
outl(PCI_BASE, (BUS_ADDRESS+(dev+(i*4))));
outl(PCI_T1_INDEX_REG, ((u32 *)pci_conf)[i]);
}
return(0);
}
/* PCI type 2 access method */
int
pci_t2_read_config(struct pci_conf_t *pci_conf, unsigned int dev)
{
int i,x;
/* bit 7 set to select the PCI configuration space */
x = (((dev & 7) << 1) | 0xf0);
outb(PCI_BASE, x);
/* bus select? */
outb(PCI_INDEX_REG, 0);
for (i=0; i<64; i++)
((u32 *)pci_conf)[i] = inl(V_BUS_ADDRESS+((dev<<8)+(i*4)));
outb(PCI_BASE,0);
return(0);
}
int
pci_t2_write_config(struct pci_conf_t *pci_conf, unsigned int dev)
{
int i,x;
/* bit 7 set to select the PCI configuration space */
x = (((dev & 7) << 1) | 0xf0);
outb(PCI_BASE, x);
/* bus select? */
outb(PCI_INDEX_REG, 0);
for (i=0; i<64; i++)
outl(V_BUS_ADDRESS+((dev<<8)+(i*4)), ((u32 *)pci_conf)[i]);
outb(PCI_BASE, 0);
return(0);
}
/* XXX: these functions below should be in a nice library. */
/* write data to port */
static void
outb(u16 port, u8 data)
{
__asm__ __volatile__(
"outb %1,%0"
:
: "Nd" (port),
"a" (data)
);
}
static void
outw(u16 port, u16 data)
{
__asm__ __volatile__(
"outw %1,%0"
:
: "Nd" (port),
"a" (data)
);
}
static void
outl(u16 port, u32 data)
{
__asm__ __volatile__(
"outl %1,%0"
:
: "Nd" (port),
"a" (data)
);
}
/* get data from port */
static u8
inb(u16 port)
{
u8 ret;
__asm__ __volatile__(
"inb %1,%0"
: "=a" (ret)
: "Nd" (port)
);
return(port);
}
static u16
inw(u16 port)
{
u16 ret;
__asm__ __volatile__(
"inw %1,%0"
: "=a" (ret)
: "Nd" (port)
);
return(ret);
}
static u32
inl(u16 port)
{
u32 ret;
__asm__ __volatile__(
"inl %1,%0"
: "=a" (ret)
: "Nd" (port)
);
return(ret);
}