pciinit.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,086 行 · 第 1/2 页

C
1,086
字号
/*++
 
Copyright (c) 1998  Microsoft Corporation
 
Module Name:
 
    Filename
 
Abstract:
 
    Routines to initialize PCI bus
 
Author:
 
    John Cooper (johncoop) 98-Jan-12
 
Environment:
 
    Wince Boot rom
 
Revision History:
 
--*/


#include <windows.h>
#include <alt_def.h>
#include <oalintr.h>
#include "romdef.h"
#include "rev.h"
#include "..\..\kernel\hal\ethernet.h"
#include <eglobal.h>
#include "ether.h"
#include "pciinit.h"
#include "vrc5074.h"



BOOL
PciInitBus(
    ULONG Bus,
    PULONG pSubordinateBus,
    PULONG pMemSize,
    PULONG pIoSize
    );

BOOL
PciInitDevice(
    ULONG Bus,
    ULONG Device,
    ULONG Function,
    PULONG pMemSize,
    PULONG pIoSize
    );

BOOL
PciInitBridge(
    ULONG Bus,
    ULONG Device,
    ULONG Function,
    PULONG pSubordinateBus,
    PULONG pMemSize,
    PULONG pIoSize
    );

BOOL
PciInitCheckBARs(
    ULONG Bus,
    ULONG Device,
    ULONG Function,
    ULONG NumberOfRegs,
    PULONG pMemSize,
    PULONG pIoSize
    );

BOOL
PciInitAllocateMemSpace(
    ULONG MemUpperBound,
    ULONG MemLowerBound,
    ULONG Bus
    );

BOOL
PciInitAllocateIoSpace(
    ULONG IoUpperBound,
    ULONG IoLowerBound,
    ULONG Bus
    );

#define MAX_SPACE 120
#define MAX_DEVICE 32
#define PCIBRIDGE_CNTRL   (0xf << 2) //sudhakar
#pragma warning (disable: 4002)
#define pci_printf()
//#define pci_printf EdbgOutputDebugString

ULONG nSpaceDesc;
SPACE_DESC SpaceDesc[MAX_SPACE];
ULONG nDev;
ULONG SortOrder;
PCI_DEVICE pDev[MAX_DEVICE];

// *** Permedia3 special case ***
#define PERM3_VENDEVID	0x000A3D3D

BOOL
PciInit(
    )
 
/*++
 
Routine Description:
 
    Initialize all PCI
 
Arguments:
 
    None.
 
Return Value:
 
    None.
 
--*/

{
    ULONG SubordinateBus = 0;
    ULONG MemSize = 0;
    ULONG IoSize = 0;
    BOOL Status = TRUE;
    ULONG Reg;

    SortOrder = 0;
    nSpaceDesc = 0;
    nDev = 0;
	

    if (!PciInitBus(0,&SubordinateBus,&MemSize,&IoSize)) {
        EdbgOutputDebugString("Too many PCI devices initializing PCI Bus\r\n");
        return FALSE;
    }
    
    if (MemSize > (PCI_BUS0_MEM_LIMIT - PCI_BUS0_MEM_BASE)) {
        EdbgOutputDebugString("Not enough memory space allocated for PCI Bus (0x%x requested)\r\n", MemSize);
        Status = FALSE;
    }
     
    if (IoSize > (PCI_BUS0_IO_LIMIT - PCI_BUS0_IO_BASE)) {
        EdbgOutputDebugString("Not enough I/O space allocated for PCI Bus (0x%x requested)\r\n", IoSize);
        Status = FALSE;
    }
     
    if (!PciInitAllocateMemSpace(PCI_BUS0_MEM_LIMIT, PCI_BUS0_MEM_BASE, 0)) {
        Status = FALSE;
        EdbgOutputDebugString("Failure allocating PCI memory space\r\n");
    }

	    if (!PciInitAllocateIoSpace(PCI_BUS0_IO_LIMIT, PCI_BUS0_IO_BASE, 0)) {
        Status = FALSE;
        EdbgOutputDebugString("Failure allocation PCI IO space\r\n");
    }
     //
    // Altoona specific interrupt routing
    //

    Reg = PCIConfig_Read(0,IDSEL_USB,0,0x3C);
    PCIConfig_Write(0,IDSEL_USB,0,0x3C,(Reg & 0xFFFFFF00) | ALNINTR_IRQ5);

    Reg = PCIConfig_Read(0,IDSEL_IDE,0,0x3C);
    PCIConfig_Write(0,IDSEL_IDE,0,0x3C,(Reg & 0xFFFFFF00) | ALNINTR_IRQ14);

    Reg = PCIConfig_Read(0,IDSEL_ENET,0,0x3C);
    PCIConfig_Write(0,IDSEL_ENET,0,0x3C,(Reg & 0xFFFFFF00) | ALNINTR_PCI_INTB);

    Reg = PCIConfig_Read(0,IDSEL_SLOT2,0,0x3C);
    PCIConfig_Write(0,IDSEL_SLOT2,0,0x3C,(Reg & 0xFFFFFF00) | ALNINTR_PCI_INTD);

    Reg = PCIConfig_Read(0,IDSEL_SLOT3,0,0x3C);
    PCIConfig_Write(0,IDSEL_SLOT3,0,0x3C,(Reg & 0xFFFFFF00) | ALNINTR_PCI_INTA);
  
    Reg = PCIConfig_Read(0,IDSEL_ISABRIDGE,0,0x3C);
    PCIConfig_Write(0,IDSEL_PMU,0,0x3C,(Reg & 0xFFFFFF00) | ALNINTR_PCI_INTC);
   
    Reg = PCIConfig_Read(0,IDSEL_PMU,0,0x3C);
    PCIConfig_Write(0,IDSEL_PMU,0,0x3C,(Reg & 0xFFFFFF00) | ALNINTR_NULL);

    //
    // Vrc5074 was excluded from everything that happened so far.
    // Come back now and do it manually
    //
    PciInitDevice(0,IDSEL_VRC5074,0,&MemSize,&IoSize);
    PCIConfig_Write(0,IDSEL_VRC5074,0,0x18,0);
    pDev[nDev].Bus = 0;
    pDev[nDev].Device = IDSEL_VRC5074;
    pDev[nDev].Function = 0;
    pDev[nDev].VendorID = VRC5074_PCIVID;
    nDev++;
    nSpaceDesc--;
    SpaceDesc[nSpaceDesc].Bus = 0;
    SpaceDesc[nSpaceDesc].Device = IDSEL_VRC5074;
    SpaceDesc[nSpaceDesc].Function = 0;
    SpaceDesc[nSpaceDesc].Offset = 0x18;
    SpaceDesc[nSpaceDesc].Bridge = 0;
    SpaceDesc[nSpaceDesc].IoSize = 0;
    SpaceDesc[nSpaceDesc].MemSize = 0x04000000;
    SpaceDesc[nSpaceDesc].SortOrder = SortOrder++;
    nSpaceDesc++;

    return Status;
}


BOOL
PciInitBus(
    ULONG Bus,
    PULONG pSubordinateBus,
    PULONG pMemSize,
    PULONG pIoSize
    )
 
/*++
 
Routine Description:
 
    Search for devices on bus to initialize
 
Arguments:
 
    Bus - supplies bus number
 
Return Value:
 
    None.
 
--*/

{
    ULONG Device;
    ULONG VendorID;
    ULONG HeaderType;
    ULONG Function;

    pci_printf("InitBus %d\r\n",Bus);

    //
    // Loop through all device numbers (slots)
    //

    for (Device = 0; Device < 32; Device++) {

        //
        // Loop through all functions
        //
           
        for (Function = 0; Function < 8; Function++) {

            //
            // Check Device Present
            //
             
            PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_BASE0,0xFFFFFFFF);
            VendorID = PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_ID);
            if (((VendorID & 0xFFFF0000) != 0xFFFF0000) &&
                ((VendorID & 0x0000FFFF) != 0x0000FFFF) &&
                ((VendorID & 0x0000FFFF) != 0x00000000) &&
                (VendorID != VRC5074_PCIVID)) {

                pDev[nDev].Bus = Bus;
                pDev[nDev].Device = Device;
                pDev[nDev].Function = Function;
                pDev[nDev].VendorID = VendorID;
                nDev++;
                if (nDev == MAX_DEVICE) {
                    return FALSE;
                }

                //
                // Check header type
                //

                HeaderType = PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_HEAD);
                if (((PPCI_BHLC)(&HeaderType))->HeadType.HeadType == 0x00) {

                    //
                    // regular device
                    //
                       
                    if (!PciInitDevice(Bus,Device,Function,pMemSize,pIoSize)) {
                        return FALSE;
                    }

                } else {

                    //
                    // Bridge device
                    //

                    if (!PciInitBridge(Bus,
                                       Device,
                                       Function,
                                       pSubordinateBus,
                                       pMemSize,
                                       pIoSize)) {
                        return FALSE;

                    }


                }

                //
				// if not a multifunction device, break out of function loop
				// and continue with next device.
                //

                if (((PPCI_BHLC)(&HeaderType))->HeadType.MultiFunctionDevice == 0) {
                    break;
                }
            } else {
                break;
            }
        }
    }
    return TRUE;
}


BOOL
PciInitDevice(
    ULONG Bus,
    ULONG Device,
    ULONG Function,
    PULONG pMemSize,
    PULONG pIoSize
    )
 
/*++
 
Routine Description:
 
    Initialize a pci device
 
Arguments:
 
    Bus,Device,Function uniquely define device
 
Return Value:
 
    None.
 
--*/

{
    ULONG Reg;

pci_printf("InitDevice %d %d %d %X\r\n",Bus,Device,Function,PCIConfig_Read(Bus,Device,Function,0));

    //
    // read the base address registers to determine space to allocate
    //

    if (!PciInitCheckBARs(Bus,Device,Function,6,pMemSize,pIoSize)) {
        return FALSE;
    }

    //
    // disable expansion ROM
    // Enable device
    //

    PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_ROM,0);
    PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_COMMAND_STATUS,0x7);
    Reg = PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_INTERRUPT);
    ((PPCI_INT)(&Reg))->InterruptLine = 0xFF;
    PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_INTERRUPT,Reg);

    return TRUE;
}


BOOL
PciInitBridge(
    ULONG Bus,
    ULONG Device,
    ULONG Function,
    PULONG pSubordinateBus,
    PULONG pMemSize,
    PULONG pIoSize
    )
 
/*++
 
Routine Description:
 
    Initialize bridge device
 
Arguments:
 
    None.
 
Return Value:
 
    None.
 
--*/

{
    ULONG BusReg;
    ULONG SecondaryMemSize;
    ULONG SecondaryIoSize;
    ULONG i;
    ULONG Reg;


    //
    // read the base address registers to determine space to allocate
    //
    
    if (!PciInitCheckBARs(Bus,Device,Function,2,pMemSize,pIoSize)) {
        return FALSE;
    }
    
    //
    // Enable bridge
    // disable expansion ROM
    // zero all the base and limit registers - these will get written later
    // zero the IRQ register
    //

   // PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_COMMAND_STATUS,0x7);
    
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_ROM,0x0);
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_PREFETCHABLE,0xffff);
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_BASE_UPPER32,0xffffffff);
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_LIMIT_UPPER32,0xffffffff);
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_MEMORY,0xffffffff);
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_IO_UPPER16,0xffff);
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_CNTRL,0x00040000);//sudhakar ISA device present

    
	 
    Reg = PCIConfig_Read(Bus,Device,Function,PCIBRIDGE_IO);
    ((PBRIDGE_IO)(&Reg))->IoLimit.Address = 0xff;
    ((PBRIDGE_IO)(&Reg))->IoBase.Address = 0xff;
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_IO,Reg);
    Reg = PCIConfig_Read(Bus,Device,Function,PCI_CONFIG_INTERRUPT);
    ((PPCI_INT)(&Reg))->InterruptLine = 0xFF;
    PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_INTERRUPT,Reg);
	
    
    PCIConfig_Write(Bus,Device,Function,PCI_CONFIG_COMMAND_STATUS,0xffff0007);//sudhakar moved to end
    
    //
    // Set the bus numbers
    // Need to set the subordinate bus as max for now, then write
    // actual number after found all downstream busses
    //

    (*pSubordinateBus)++;
    BusReg = PCIConfig_Read(Bus,Device,Function,PCIBRIDGE_BUS_NUMBER);
    ((PBRIDGE_BUS)(&BusReg))->PrimaryBusNumber = (BYTE)Bus;
    ((PBRIDGE_BUS)(&BusReg))->SecondaryBusNumber = (BYTE)(*pSubordinateBus);
    ((PBRIDGE_BUS)(&BusReg))->SubordinateBusNumber = 0xFF;
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_BUS_NUMBER,BusReg);

    pci_printf("InitBridge %d %d %d %d %X\r\n",Bus,Device,Function,*pSubordinateBus,PCIConfig_Read(Bus,Device,Function,0));
 
      
    //
    // Call initbus routine recursively
    //

    SecondaryMemSize = 0;
    SecondaryIoSize = 0;
    if (!PciInitBus(*pSubordinateBus,
                    pSubordinateBus,
                    &SecondaryMemSize,
                    &SecondaryIoSize)) {
        return FALSE;
    }
     
    //
    // fill in the proper value for subordinate bus
    //

    ((PBRIDGE_BUS)(&BusReg))->SubordinateBusNumber = (BYTE)(*pSubordinateBus);
    PCIConfig_Write(Bus,Device,Function,PCIBRIDGE_BUS_NUMBER,BusReg);

    //
    // Add bridge to list to come back later and fill in limit registers
    // Round up space required by secondary bus to 1MB boundary and then
    // align to proper boundary after that
    //

    SecondaryMemSize = (SecondaryMemSize + 0x000FFFFF) & 0xFFF00000;
    if (((SecondaryMemSize - 1) & (SecondaryMemSize)) != 0) {
        for (i = 31; i > 1; i--) {
            if (SecondaryMemSize & (1 << i)) {
                SecondaryMemSize = (1 << (i+1));
                break;
            }
        }
    }

    SecondaryIoSize = (SecondaryIoSize + 0x00000FFF) & 0xFFFFF000;
    if (((SecondaryIoSize - 1) & (SecondaryIoSize)) != 0) {
        for (i = 31; i > 1; i--) {
            if (SecondaryIoSize & (1 << i)) {
                SecondaryIoSize = (1 << (i+1));
                break;
            }
        }
    }

    pci_printf("Bridgespace %08x %08x %08x\r\n",SecondaryMemSize,SecondaryIoSize,BusReg);

    SpaceDesc[nSpaceDesc].Bus = Bus;
    SpaceDesc[nSpaceDesc].Device = Device;
    SpaceDesc[nSpaceDesc].Function = Function;
    SpaceDesc[nSpaceDesc].MemSize = SecondaryMemSize;
    SpaceDesc[nSpaceDesc].IoSize = SecondaryIoSize;
    SpaceDesc[nSpaceDesc].Bridge = 1;
    SpaceDesc[nSpaceDesc].SecondaryBus =
        ((PBRIDGE_BUS)(&BusReg))->SecondaryBusNumber;
    nSpaceDesc++;
    if (nSpaceDesc == MAX_SPACE) {
        return FALSE;
    }

    *pMemSize += SecondaryMemSize;
    *pIoSize += SecondaryIoSize;

    return TRUE;

}



BOOL
PciInitCheckBARs(
    ULONG Bus,
    ULONG Device,
    ULONG Function,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?