📄 pcilib.c
字号:
/*
* Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
* All rights reserved.
*
* This software is copyrighted by and is the sole property of
* VIA Networking Technologies, Inc. This software may only be used
* in accordance with the corresponding license agreement. Any unauthorized
* use, duplication, transmission, distribution, or disclosure of this
* software is expressly forbidden.
*
* This software is provided by VIA Networking Technologies, Inc. "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 VIA Networking Technologies, Inc.
* be liable for any direct, indirect, incidental, special, exemplary, or
* consequential damages.
*
*
* File: pcilib.c
*
* Purpose: Diagnose PCI
*
* Author: Henry Lin
*
* Date: July 8, 2005
*
* Functions:
*
* Revision History:
*
*/
#if !defined(__STR_H__)
#include "str.h"
#endif
#if !defined(__DEVICE_H__)
#include "device.h"
#endif
#if !defined(__PCIDRIVER_H__)
#include "pcidriver.h"
#endif
#if !defined(__PCILIB_H__)
#include "pcilib.h"
#endif
#include "armboot.h"
/*--------------------- Static Definitions -------------------------*/
#define DBG_PCILIB 0
//#define Print printf
#define Print(...) FUNC_NULL()
#define EXTINTMAX 6 /* s3c2510 has 6 external interrupt pins */
#define INTA VEC_PCI_H_INT+EXTINTMAX
#define INTB VEC_PCI_H_INT+EXTINTMAX
#define INTC VEC_PCI_H_INT+EXTINTMAX
#define INTD VEC_PCI_H_INT+EXTINTMAX
/*--------------------- Static Types ------------------------------*/
/*--------------------- Static Macros -----------------------------*/
#define PCI_ALLOC_MEM_BASE 0x0 /* Set to PCIBATAPM [31:28]*/
#define PCI_ALLOC_IO_BASE 0x0 /* Set to PCIBATAPI [31:26]*/
#define PCI_EXP_ROM_ENABLE 0x1
#define PCIMode() (!(ASIC_PCI_PCICON & PCICON_PCCARDMODE))
#define HostMode() (ASIC_PCI_PCICON & PCI_HST)
#define PCIDRV_HostMode() (PCIMode() && HostMode())
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
// queue of PCI devices
PCIDevice_t *g_sPCIDeviceList = NULL;
// root of the tree of PCI devices/buses
PCIDevice_t *g_sPCIroot = NULL;
PCIDevice_t g_arrDev[30];
UINT16 g_u16DevUseIndx = 0;
UINT32 pciScaned;
UINT32 g_u32PciIoBase;
UINT32 g_u32PciMemBase;
/*--------------------- Static Functions --------------------------*/
char * getDeviceClass (UINT id, UINT device, UINT devClass);
static UINT32 PCIir_AllocateMemSpace (UINT32 size);
UINT32 PCIir_AllocateIOSpace (UINT32 size);
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
void PCILIB_Scan(UINT32* pu32IoBA, UINT32* pu32MemBA)
{
UINT32 u32Data;
/* Must be PCI host to initialise the bus */
if (PCIDRV_HostMode()) {
/* initialise the bus */
Print ("Initializing PCI");
/* Where in IO and Memory do we start allocating space from? */
g_u32PciIoBase = PCI_ALLOC_IO_BASE; // for PCI IO Address Allocation
g_u32PciMemBase = PCI_ALLOC_MEM_BASE; // for PCI Memory Address Allocation
PCILIB_Init(); // Scan PCI bus
//Get I/O and Mem base address for VT3268
u32Data = PCICFG_Read32(0, 1, 0, PCIHBAR1_OFF); //MIO
*pu32MemBA = (u32Data & 0xFFFFFFF0); //mask [3:0]
u32Data = PCICFG_Read32(0, 1, 0, PCIHBAR0_OFF); //PIO
*pu32IoBA = (u32Data & 0xFFFFFFFE); //mask Space Indicator bit
Print ("...done \n");
/* dump out the contents of each occupied slot */
PCIr_ForEveryDevice (PCI_Action);
pciScaned = 1;
}
else {
Print("Sorry, not PCI host - can't scan the bus \n");
}
}
/*============================================================================
*
* parameters: none
*
* description: This routine initialises the PCI subsystem for this board.
*
* calls: none
*
* returns: void.
*
*/
void PCILIB_Init (void)
{
// Create the root (host) PCI bridge
g_sPCIroot = PCIir_AllocatePCIDevice ();
g_sPCIroot->flags.bridge = 1;
g_sPCIroot->bridge.number = g_sPCIroot->bridge.primary =
g_sPCIroot->bridge.secondary = g_sPCIroot->bridge.subordinate = 0;
g_sPCIroot->bus = 0;
// Init the device list
g_sPCIDeviceList= NULL;
// Scan the PCI bus looking for all available devices/bridges.
// This builds a set of internal descriptors describing the topology
// of the PCI subsystem. It numbers the pci-pci bridges as it
// scans.
g_sPCIroot->bridge.subordinate = PCILIB_ScanPCI(g_sPCIroot);
// Allocate the PCI devices space in IO and Memory
PCIir_ConfigurePCIDevices (g_sPCIroot);
}
/*============================================================================
* description: this routine will insert all known fixed devices into the
* device node tree. It will then scan the PCI buses looking
* for valid devices.
*
* returns: device number?
*/
UINT8 PCILIB_ScanPCI(PCIDevice_t * bus)
{
UINT32 maxSlot;
UINT32 slot, is_a_multi_function_device = 0;
UINT32 max;
UINT32 func, offset, device;
UINT32 devClass;
UINT16 vendor;
max = 0;
// if this host doesn't support PCI, do not do anything
if (PCIDRV_HostMode()) {
/* maximum subordinate bus number (used in PCI bus numbering) */
max = bus->bridge.secondary;
/* how many slots we scan depends on whether this is the primary
PCI bus or we're going through one or more bridges */
maxSlot = (bus->bridge.number == 0) ? PCI_MAX_SLOT : 32;
/* now scan all possible buses and slots looking for devices */
slot = maxSlot+1; // slot21~slot1 and slot0(=2510 PCI Host Target)
do {
slot--;
// assume that it is not a multi-function device
is_a_multi_function_device = 0;
/* now scan all functions */
for (func = 0; func< 8; func++)
{
// if it is not a multi-function device, do not treat it as one..
if ((func != 0) && !is_a_multi_function_device)
continue;
/* read the device configuration space */
vendor = PCICFG_Read16 (bus->bridge.number, slot, func,PCIHVID_OFF);
/* check if it responds */
if (vendor != PCI_NOTFITTED)
{
UINT8 header_type;
PCIDevice_t *newDev;
// read the header type (this may be a multi-function device
header_type = PCICFG_Read8 (bus->bridge.number, slot, func, PCIHHEADER_OFF);
if (func == 0)
{
is_a_multi_function_device = ((header_type & 0x80) != 0);
}
// yup, get the device and create PCI device data structure
offset = PCIHDID_OFF;
device = PCICFG_Read16 (bus->bridge.number, slot, func, offset);
newDev = PCIr_AddPCIDevice (bus, bus->bridge.number, slot, func, vendor, device);
// is it a PCI-PCI bridge (make this a naturally aligned read)?
offset = PCIHCLASS_OFF;
devClass = (0x00FFFFFF & PCICFG_Read32 (bus->bridge.number, slot, func,offset)) ;
if ((devClass >> 16) == PCI_BRIDGE_CLASS)
{
if (((devClass & 0xFF00) >> 8) == PCI_2PCI_SUB)
{
UINT32 buses, command;
// init
buses = 0 ;
// initialise it
newDev->flags.bridge = TRUE;
newDev->bridge.number = newDev->bridge.secondary = ++max;
newDev->bridge.primary = bus->bridge.secondary;
newDev->bridge.subordinate = 0xFF; // until we know better
// Clear all status bits and turn off memory, IO and master enables
command = PCICFG_Read16 (bus->bridge.number, slot, func, PCIHSC_OFF);
PCICFG_Write16 (bus->bridge.number, slot, func, PCIHCMD_OFF, 0x0000);
PCICFG_Write16 (bus->bridge.number, slot, func, PCIHST_OFF, 0xFFFF);
// configure the bus numbers for this bridge
buses &= 0xFF000000;
buses |= ((newDev->bridge.primary << 0) |
(newDev->bridge.secondary << 8) |
(newDev->bridge.subordinate << 16));
offset = 0x18;
PCICFG_Write32 (bus->bridge.number, slot, func, offset, buses);
// scan all subordinate buses
max = PCILIB_ScanPCI(newDev);
// set the subordinate bus number to its real value
newDev->bridge.subordinate = max;
buses = (buses & 0xff00ffff) | (max << 16);
offset = 0x18;
PCICFG_Write32 (bus->bridge.number, slot, func, offset, buses);
}
}
}
}
} while (slot!=0);
}
// return the number of the subordinate bus
return max;
}
/*============================================================================
*
* description: Allocate new PCIDevice structure.
*
* returns: Pointer to a devNodeType or NULL if it fails.
*
*/
PCIDevice_t * PCIir_AllocatePCIDevice (void)
{
PCIDevice_t *newDev;
newDev = &g_arrDev[g_u16DevUseIndx++];
// initialise it
if (newDev != NULL)
{
newDev->flags.bridge = 0;
newDev->next = NULL;
newDev->sibling = NULL;
newDev->parent = NULL;
newDev->bridge.children = NULL;
}
// return a pointer to it
return newDev;
}
/*============================================================================
*
* description: this routine will insert this device into the devNode tree.
* It will keep track of available devNodes.
*
* returns: void
*
*/
PCIDevice_t * PCIr_AddPCIDevice (PCIDevice_t * bridge, UINT32 bus, UINT32 slot, UINT32 func,
UINT16 vendor, UINT16 device)
{
PCIDevice_t *newDev;
/* first allocate a new one */
newDev = PCIir_AllocatePCIDevice ();
if (newDev != NULL)
{
// fill it out
newDev->bus = bus;
newDev->slot = slot;
newDev->func = func;
newDev->vendor = vendor;
newDev->device = device;
// enqueue it [1]
newDev->next = g_sPCIDeviceList;
g_sPCIDeviceList = newDev;
// enqueue it [2]
newDev->sibling = bridge->bridge.children;
bridge->bridge.children = newDev;
newDev->parent = bridge;
}
// return it
return newDev;
}
void PCI_Action (UINT32 bus, UINT32 slot,UINT32 func)
{
UINT32 data, offset = PCIHBAR0_OFF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -