forked from Imagelibrary/rtems
2007-09-06 Daniel Hellstrom <daniel@gaisler.com>
* pci/pci.c: New file.
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
2007-09-06 Daniel Hellstrom <daniel@gaisler.com>
|
||||||
|
|
||||||
|
* pci/pci.c: New file.
|
||||||
|
|
||||||
2007-09-06 Daniel Hellstrom <daniel@gaisler.com>
|
2007-09-06 Daniel Hellstrom <daniel@gaisler.com>
|
||||||
|
|
||||||
* cchip/cchip.c, include/cchip.h, include/rasta.h,
|
* cchip/cchip.c, include/cchip.h, include/rasta.h,
|
||||||
|
|||||||
675
c/src/lib/libbsp/sparc/leon2/pci/pci.c
Normal file
675
c/src/lib/libbsp/sparc/leon2/pci/pci.c
Normal file
@@ -0,0 +1,675 @@
|
|||||||
|
/*
|
||||||
|
* pci.c : this file contains basic PCI Io functions.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 valette@crf.canon.fr
|
||||||
|
*
|
||||||
|
* This code is heavily inspired by the public specification of STREAM V2
|
||||||
|
* that can be found at :
|
||||||
|
*
|
||||||
|
* <http://www.chorus.com/Documentation/index.html> by following
|
||||||
|
* the STREAM API Specification Document link.
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.rtems.com/license/LICENSE.
|
||||||
|
*
|
||||||
|
* pci.c,v 1.2.4.4 2004/11/10 22:15:01 joel Exp
|
||||||
|
*
|
||||||
|
* Till Straumann, <strauman@slac.stanford.edu>, 1/2002
|
||||||
|
* - separated bridge detection code out of this file
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Adapted to LEON2 AT697 PCI
|
||||||
|
* Copyright (C) 2006 Gaisler Research
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pci.h>
|
||||||
|
#include <rtems/bspIo.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Define PCI_INFO to get a listing of configured devices at boot time */
|
||||||
|
#define PCI_INFO 1
|
||||||
|
|
||||||
|
/* #define DEBUG 1 */
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DBG(x...) printk(x)
|
||||||
|
#else
|
||||||
|
#define DBG(x...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* allow for overriding these definitions */
|
||||||
|
#ifndef PCI_CONFIG_ADDR
|
||||||
|
#define PCI_CONFIG_ADDR 0xcf8
|
||||||
|
#endif
|
||||||
|
#ifndef PCI_CONFIG_DATA
|
||||||
|
#define PCI_CONFIG_DATA 0xcfc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PCI_INVALID_VENDORDEVICEID 0xffffffff
|
||||||
|
#define PCI_MULTI_FUNCTION 0x80
|
||||||
|
|
||||||
|
/* define a shortcut */
|
||||||
|
#define pci BSP_pci_configuration
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit encode for PCI_CONFIG_HEADER_TYPE register
|
||||||
|
*/
|
||||||
|
unsigned char ucMaxPCIBus;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
volatile unsigned int pciid1; /* 0x80000100 - PCI Device identification register 1 */
|
||||||
|
volatile unsigned int pcisc; /* 0x80000104 - PCI Status & Command */
|
||||||
|
volatile unsigned int pciid2; /* 0x80000108 - PCI Device identification register 2 */
|
||||||
|
volatile unsigned int pcibhlc; /* 0x8000010c - BIST, Header type, Cache line size register */
|
||||||
|
volatile unsigned int mbar1; /* 0x80000110 - Memory Base Address Register 1 */
|
||||||
|
volatile unsigned int mbar2; /* 0x80000114 - Memory Base Address Register 2 */
|
||||||
|
volatile unsigned int iobar3; /* 0x80000118 - IO Base Address Register 3 */
|
||||||
|
volatile unsigned int dummy1[4]; /* 0x8000011c - 0x80000128 */
|
||||||
|
volatile unsigned int pcisid; /* 0x8000012c - Subsystem identification register */
|
||||||
|
volatile unsigned int dummy2; /* 0x80000130 */
|
||||||
|
volatile unsigned int pcicp; /* 0x80000134 - PCI capabilities pointer register */
|
||||||
|
volatile unsigned int dummy3; /* 0x80000138 */
|
||||||
|
volatile unsigned int pcili; /* 0x8000013c - PCI latency interrupt register */
|
||||||
|
volatile unsigned int pcirt; /* 0x80000140 - PCI retry, trdy config */
|
||||||
|
volatile unsigned int pcicw; /* 0x80000144 - PCI configuration write register */
|
||||||
|
volatile unsigned int pcisa; /* 0x80000148 - PCI Initiator Start Address */
|
||||||
|
volatile unsigned int pciiw; /* 0x8000014c - PCI Initiator Write Register */
|
||||||
|
volatile unsigned int pcidma; /* 0x80000150 - PCI DMA configuration register */
|
||||||
|
volatile unsigned int pciis; /* 0x80000154 - PCI Initiator Status Register */
|
||||||
|
volatile unsigned int pciic; /* 0x80000158 - PCI Initiator Configuration */
|
||||||
|
volatile unsigned int pcitpa; /* 0x8000015c - PCI Target Page Address Register */
|
||||||
|
volatile unsigned int pcitsc; /* 0x80000160 - PCI Target Status-Command Register */
|
||||||
|
volatile unsigned int pciite; /* 0x80000164 - PCI Interrupt Enable Register */
|
||||||
|
volatile unsigned int pciitp; /* 0x80000168 - PCI Interrupt Pending Register */
|
||||||
|
volatile unsigned int pciitf; /* 0x8000016c - PCI Interrupt Force Register */
|
||||||
|
volatile unsigned int pcid; /* 0x80000170 - PCI Data Register */
|
||||||
|
volatile unsigned int pcibe; /* 0x80000174 - PCI Burst End Register */
|
||||||
|
volatile unsigned int pcidmaa; /* 0x80000178 - PCI DMA Address Register */
|
||||||
|
} AT697_PCI_Map;
|
||||||
|
|
||||||
|
AT697_PCI_Map *pcic = (AT697_PCI_Map *) 0x80000100;
|
||||||
|
|
||||||
|
#define PCI_MEM_START 0xa0000000
|
||||||
|
#define PCI_MEM_END 0xf0000000
|
||||||
|
#define PCI_MEM_SIZE (PCI_MEM_START - PCI_MEM_END)
|
||||||
|
|
||||||
|
|
||||||
|
struct pci_res {
|
||||||
|
unsigned int size;
|
||||||
|
unsigned char bar;
|
||||||
|
unsigned char devfn;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The configuration access functions uses the DMA functionality of the
|
||||||
|
* AT697 pci controller to be able access all slots
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_read_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int *val) {
|
||||||
|
|
||||||
|
volatile unsigned int data;
|
||||||
|
|
||||||
|
if (offset & 3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
|
||||||
|
pcic->pciitp = 0xff; /* clear interrupts */
|
||||||
|
|
||||||
|
pcic->pcisa = ( 1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f);
|
||||||
|
pcic->pcidma = 0xa01;
|
||||||
|
pcic->pcidmaa = (unsigned int) &data;
|
||||||
|
|
||||||
|
while (pcic->pciitp == 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
pcic->pciitp = 0xff; /* clear interrupts */
|
||||||
|
|
||||||
|
if (pcic->pcisc & 0x20000000) { /* Master Abort */
|
||||||
|
pcic->pcisc |= 0x20000000;
|
||||||
|
*val = 0xffffffff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*val = data;
|
||||||
|
|
||||||
|
DBG("pci_read - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n", bus, slot, function, offset, (1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f), *val);
|
||||||
|
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_read_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short *val) {
|
||||||
|
unsigned int v;
|
||||||
|
|
||||||
|
if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
|
||||||
|
pci_read_config_dword(bus, slot, function, offset&~3, &v);
|
||||||
|
*val = 0xffff & (v >> (8*(offset & 3)));
|
||||||
|
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_read_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char *val) {
|
||||||
|
unsigned int v;
|
||||||
|
|
||||||
|
pci_read_config_dword(bus, slot, function, offset&~3, &v);
|
||||||
|
|
||||||
|
*val = 0xff & (v >> (8*(offset & 3)));
|
||||||
|
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_write_config_dword(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned int val) {
|
||||||
|
|
||||||
|
if (offset & 3) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
|
||||||
|
pcic->pciitp = 0xff; /* clear interrupts */
|
||||||
|
|
||||||
|
pcic->pcisa = ( 1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f);
|
||||||
|
pcic->pcidma = 0xb01;
|
||||||
|
pcic->pcidmaa = (unsigned int) &val;
|
||||||
|
|
||||||
|
while (pcic->pciitp == 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (pcic->pcisc & 0x20000000) { /* Master Abort */
|
||||||
|
pcic->pcisc |= 0x20000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcic->pciitp = 0xff; /* clear interrupts */
|
||||||
|
|
||||||
|
/* DBG("pci write - bus: %d, dev: %d, fn: %d, off: %d => addr: %x, val: %x\n", bus, slot, function, offset, (1<<(11+slot) ) | ((function & 7)<<8) | (offset&0x3f), val); */
|
||||||
|
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_write_config_word(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned short val) {
|
||||||
|
unsigned int v;
|
||||||
|
|
||||||
|
if (offset & 1) return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
|
||||||
|
pci_read_config_dword(bus, slot, function, offset&~3, &v);
|
||||||
|
|
||||||
|
v = (v & ~(0xffff << (8*(offset&3)))) | ((0xffff&val) << (8*(offset&3)));
|
||||||
|
|
||||||
|
return pci_write_config_dword(bus, slot, function, offset&~3, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pci_write_config_byte(unsigned char bus, unsigned char slot, unsigned char function, unsigned char offset, unsigned char val) {
|
||||||
|
unsigned int v;
|
||||||
|
|
||||||
|
pci_read_config_dword(bus, slot, function, offset&~3, &v);
|
||||||
|
|
||||||
|
v = (v & ~(0xff << (8*(offset&3)))) | ((0xff&val) << (8*(offset&3)));
|
||||||
|
|
||||||
|
return pci_write_config_dword(bus, slot, function, offset&~3, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const pci_config_access_functions pci_access_functions = {
|
||||||
|
pci_read_config_byte,
|
||||||
|
pci_read_config_word,
|
||||||
|
pci_read_config_dword,
|
||||||
|
pci_write_config_byte,
|
||||||
|
pci_write_config_word,
|
||||||
|
pci_write_config_dword
|
||||||
|
};
|
||||||
|
|
||||||
|
pci_config BSP_pci_configuration = { (volatile unsigned char*)PCI_CONFIG_ADDR,
|
||||||
|
(volatile unsigned char*)PCI_CONFIG_DATA,
|
||||||
|
&pci_access_functions };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void init_at697_pci(void) {
|
||||||
|
|
||||||
|
/* Reset */
|
||||||
|
pcic->pciic = 0xffffffff;
|
||||||
|
|
||||||
|
/* Map system RAM at pci address 0x40000000 and system SDRAM to pci address 0x60000000 */
|
||||||
|
pcic->mbar1 = 0x40000000;
|
||||||
|
pcic->mbar2 = 0x60000000;
|
||||||
|
pcic->pcitpa = 0x40006000;
|
||||||
|
|
||||||
|
/* Enable PCI master and target memory command response */
|
||||||
|
pcic->pcisc |= 0x40 | 0x6;
|
||||||
|
|
||||||
|
/* Set latency timer to 64 */
|
||||||
|
pcic->pcibhlc = 0x00004000;
|
||||||
|
|
||||||
|
/* Set Inititator configuration so that AHB slave accesses generate memory read/write commands */
|
||||||
|
pcic->pciic = 0x41;
|
||||||
|
|
||||||
|
pcic->pciite = 0xff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* May not pass a 1k boundary */
|
||||||
|
int dma_from_pci_1k(unsigned int addr, unsigned int paddr, unsigned char len) {
|
||||||
|
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (addr & 3) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcic->pciitp = 0xff; /* clear interrupts */
|
||||||
|
|
||||||
|
pcic->pcisa = paddr;
|
||||||
|
pcic->pcidma = 0xc00 | len;
|
||||||
|
pcic->pcidmaa = addr;
|
||||||
|
|
||||||
|
while (pcic->pciitp == 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (pcic->pciitp & 0x7F) {
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcic->pciitp = 0xff; /* clear interrupts */
|
||||||
|
|
||||||
|
if (pcic->pcisc & 0x20000000) { /* Master Abort */
|
||||||
|
pcic->pcisc |= 0x20000000;
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* May not pass a 1k boundary */
|
||||||
|
int dma_to_pci_1k(unsigned int addr, unsigned int paddr, unsigned char len) {
|
||||||
|
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (addr & 3) return -1;
|
||||||
|
|
||||||
|
pcic->pciitp = 0xff; /* clear interrupts */
|
||||||
|
|
||||||
|
pcic->pcisa = paddr;
|
||||||
|
pcic->pcidma = 0x700 | len;
|
||||||
|
pcic->pcidmaa = addr;
|
||||||
|
|
||||||
|
while (pcic->pciitp == 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (pcic->pciitp & 0x7F) retval = -1;
|
||||||
|
|
||||||
|
pcic->pciitp = 0xff; /* clear interrupts */
|
||||||
|
|
||||||
|
if (pcic->pcisc & 0x20000000) { /* Master Abort */
|
||||||
|
pcic->pcisc |= 0x20000000;
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer len number of words from addr to paddr */
|
||||||
|
int dma_to_pci(unsigned int addr, unsigned int paddr, unsigned int len) {
|
||||||
|
|
||||||
|
int tmp_len;
|
||||||
|
|
||||||
|
/* Align to 1k boundary */
|
||||||
|
tmp_len = ((addr + 1024) & 0xfffffc00) - addr;
|
||||||
|
|
||||||
|
tmp_len = (tmp_len/4 < len) ? tmp_len : (len*4);
|
||||||
|
|
||||||
|
if (dma_to_pci_1k(addr, paddr, tmp_len/4) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
addr += tmp_len;
|
||||||
|
paddr += tmp_len;
|
||||||
|
len -= tmp_len/4;
|
||||||
|
|
||||||
|
/* Transfer all 1k blocks */
|
||||||
|
while (len >= 128) {
|
||||||
|
|
||||||
|
if (dma_to_pci_1k(addr, paddr, 128) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
addr += 512;
|
||||||
|
paddr += 512;
|
||||||
|
len -= 128;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer last words */
|
||||||
|
if (len) return dma_to_pci_1k(addr, paddr, len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer len number of words from paddr to addr */
|
||||||
|
int dma_from_pci(unsigned int addr, unsigned int paddr, unsigned int len) {
|
||||||
|
|
||||||
|
int tmp_len;
|
||||||
|
|
||||||
|
/* Align to 1k boundary */
|
||||||
|
tmp_len = ((addr + 1024) & 0xfffffc00) - addr;
|
||||||
|
|
||||||
|
tmp_len = (tmp_len/4 < len) ? tmp_len : (len*4);
|
||||||
|
|
||||||
|
if (dma_from_pci_1k(addr, paddr, tmp_len/4) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
addr += tmp_len;
|
||||||
|
paddr += tmp_len;
|
||||||
|
len -= tmp_len/4;
|
||||||
|
|
||||||
|
/* Transfer all 1k blocks */
|
||||||
|
while (len >= 128) {
|
||||||
|
|
||||||
|
if (dma_from_pci_1k(addr, paddr, 128) < 0)
|
||||||
|
return -1;
|
||||||
|
addr += 512;
|
||||||
|
paddr += 512;
|
||||||
|
len -= 128;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer last words */
|
||||||
|
if (len) return dma_from_pci_1k(addr, paddr, len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_mem_enable(unsigned char bus, unsigned char slot, unsigned char function) {
|
||||||
|
unsigned int data;
|
||||||
|
|
||||||
|
pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
|
||||||
|
pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MEMORY);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_master_enable(unsigned char bus, unsigned char slot, unsigned char function) {
|
||||||
|
unsigned int data;
|
||||||
|
|
||||||
|
pci_read_config_dword(0, slot, function, PCI_COMMAND, &data);
|
||||||
|
pci_write_config_dword(0, slot, function, PCI_COMMAND, data | PCI_COMMAND_MASTER);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void swap_res(struct pci_res **p1, struct pci_res **p2) {
|
||||||
|
|
||||||
|
struct pci_res *tmp = *p1;
|
||||||
|
*p1 = *p2;
|
||||||
|
*p2 = tmp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pci_allocate_resources
|
||||||
|
*
|
||||||
|
* This function scans the bus and assigns PCI addresses to all devices. It handles both
|
||||||
|
* single function and multi function devices. All allocated devices are enabled and
|
||||||
|
* latency timers are set to 40.
|
||||||
|
*
|
||||||
|
* NOTE that it only allocates PCI memory space devices. IO spaces are not enabled.
|
||||||
|
* Also, it does not handle pci-pci bridges. They are left disabled.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void pci_allocate_resources(void) {
|
||||||
|
|
||||||
|
unsigned int slot, numfuncs, func, id, pos, size, tmp, i, swapped, addr, dev, fn;
|
||||||
|
unsigned char header;
|
||||||
|
struct pci_res **res;
|
||||||
|
|
||||||
|
res = (struct pci_res **) malloc(sizeof(struct pci_res *)*32*8*6);
|
||||||
|
|
||||||
|
for (i = 0; i < 32*8*6; i++) {
|
||||||
|
res[i] = (struct pci_res *) malloc(sizeof(struct pci_res));
|
||||||
|
res[i]->size = 0;
|
||||||
|
res[i]->devfn = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(slot = 0; slot< PCI_MAX_DEVICES; slot++) {
|
||||||
|
|
||||||
|
pci_read_config_dword(0, slot, 0, PCI_VENDOR_ID, &id);
|
||||||
|
|
||||||
|
if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
|
||||||
|
/*
|
||||||
|
* This slot is empty
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
|
||||||
|
|
||||||
|
if(header & PCI_MULTI_FUNCTION) {
|
||||||
|
numfuncs = PCI_MAX_FUNCTIONS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
numfuncs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(func = 0; func < numfuncs; func++) {
|
||||||
|
|
||||||
|
pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &id);
|
||||||
|
if(id == PCI_INVALID_VENDORDEVICEID || id == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_read_config_dword(0, slot, func, PCI_CLASS_REVISION, &tmp);
|
||||||
|
tmp >>= 16;
|
||||||
|
if (tmp == PCI_CLASS_BRIDGE_PCI) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pos = 0; pos < 6; pos++) {
|
||||||
|
pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0xffffffff);
|
||||||
|
pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), &size);
|
||||||
|
|
||||||
|
if (size == 0 || size == 0xffffffff || (size & 0xff) != 0) {
|
||||||
|
pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + (pos<<2), 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
res[slot*8*6+func*6+pos]->size = ~size+1;
|
||||||
|
res[slot*8*6+func*6+pos]->devfn = slot*8 + func;
|
||||||
|
res[slot*8*6+func*6+pos]->bar = pos;
|
||||||
|
|
||||||
|
DBG("Slot: %d, function: %d, bar%d size: %x\n", slot, func, pos, ~size+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Sort the resources in descending order */
|
||||||
|
|
||||||
|
swapped = 1;
|
||||||
|
while (swapped == 1) {
|
||||||
|
swapped = 0;
|
||||||
|
for (i = 0; i < 32*8*6-1; i++) {
|
||||||
|
if (res[i]->size < res[i+1]->size) {
|
||||||
|
swap_res(&res[i], &res[i+1]);
|
||||||
|
swapped = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign the BARs */
|
||||||
|
|
||||||
|
addr = PCI_MEM_START;
|
||||||
|
for (i = 0; i < 32*8*6; i++) {
|
||||||
|
|
||||||
|
if (res[i]->size == 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ( (addr + res[i]->size) > PCI_MEM_END) {
|
||||||
|
printk("Out of PCI memory space, all devices not configured.\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = res[i]->devfn >> 3;
|
||||||
|
fn = res[i]->devfn & 7;
|
||||||
|
|
||||||
|
DBG("Assigning PCI addr %x to device %d, function %d, bar %d\n", addr, dev, fn, res[i]->bar);
|
||||||
|
pci_write_config_dword(0, dev, fn, PCI_BASE_ADDRESS_0+res[i]->bar*4, addr);
|
||||||
|
addr += res[i]->size;
|
||||||
|
|
||||||
|
/* Set latency timer to 64 */
|
||||||
|
pci_read_config_dword(0, dev, fn, 0xC, &tmp);
|
||||||
|
pci_write_config_dword(0, dev, fn, 0xC, tmp|0x4000);
|
||||||
|
|
||||||
|
pci_mem_enable(0, dev, fn);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
#ifdef PCI_INFO
|
||||||
|
printk("\nPCI devices found and configured:\n");
|
||||||
|
for (slot = 0; slot < PCI_MAX_DEVICES; slot++) {
|
||||||
|
|
||||||
|
pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &header);
|
||||||
|
|
||||||
|
if(header & PCI_MULTI_FUNCTION) {
|
||||||
|
numfuncs = PCI_MAX_FUNCTIONS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
numfuncs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (func = 0; func < numfuncs; func++) {
|
||||||
|
|
||||||
|
pci_read_config_dword(0, slot, func, PCI_COMMAND, &tmp);
|
||||||
|
|
||||||
|
if (tmp & PCI_COMMAND_MEMORY) {
|
||||||
|
|
||||||
|
pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &id);
|
||||||
|
|
||||||
|
if (id == PCI_INVALID_VENDORDEVICEID || id == 0) continue;
|
||||||
|
|
||||||
|
printk("\nSlot %d function: %d\nVendor id: 0x%x, device id: 0x%x\n", slot, func, id & 0xffff, id>>16);
|
||||||
|
|
||||||
|
for (pos = 0; pos < 6; pos++) {
|
||||||
|
pci_read_config_dword(0, slot, func, PCI_BASE_ADDRESS_0 + pos*4, &tmp);
|
||||||
|
|
||||||
|
if (tmp != 0 && tmp != 0xffffffff && (tmp & 0xff) == 0) {
|
||||||
|
|
||||||
|
printk("\tBAR %d: %x\n", pos, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
printk("\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printk("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i = 0; i < 1536; i++) {
|
||||||
|
free(res[i]);
|
||||||
|
}
|
||||||
|
free(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine determines the maximum bus number in the system
|
||||||
|
*/
|
||||||
|
int init_pci()
|
||||||
|
{
|
||||||
|
unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
|
||||||
|
unsigned char ucHeader;
|
||||||
|
unsigned char ucMaxSubordinate;
|
||||||
|
unsigned int ulClass, ulDeviceID;
|
||||||
|
|
||||||
|
init_at697_pci();
|
||||||
|
pci_allocate_resources();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan PCI bus 0 looking for PCI-PCI bridges
|
||||||
|
*/
|
||||||
|
for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
0,
|
||||||
|
PCI_VENDOR_ID,
|
||||||
|
&ulDeviceID);
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
|
||||||
|
/*
|
||||||
|
* This slot is empty
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(void)pci_read_config_byte(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
0,
|
||||||
|
PCI_HEADER_TYPE,
|
||||||
|
&ucHeader);
|
||||||
|
if(ucHeader&PCI_MULTI_FUNCTION) {
|
||||||
|
ucNumFuncs=PCI_MAX_FUNCTIONS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ucNumFuncs=1;
|
||||||
|
}
|
||||||
|
for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_VENDOR_ID,
|
||||||
|
&ulDeviceID);
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
|
||||||
|
/*
|
||||||
|
* This slot/function is empty
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This slot/function has a device fitted.
|
||||||
|
*/
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_CLASS_REVISION,
|
||||||
|
&ulClass);
|
||||||
|
ulClass >>= 16;
|
||||||
|
if (ulClass == PCI_CLASS_BRIDGE_PCI) {
|
||||||
|
/*
|
||||||
|
* We have found a PCI-PCI bridge
|
||||||
|
*/
|
||||||
|
(void)pci_read_config_byte(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_SUBORDINATE_BUS,
|
||||||
|
&ucMaxSubordinate);
|
||||||
|
if(ucMaxSubordinate>ucMaxPCIBus) {
|
||||||
|
ucMaxPCIBus=ucMaxSubordinate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the number of PCI busses in the system
|
||||||
|
*/
|
||||||
|
unsigned char BusCountPCI()
|
||||||
|
{
|
||||||
|
return(ucMaxPCIBus+1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user