pcidriver.c
来自「source code of armboot for s3c4510」· C语言 代码 · 共 222 行
C
222 行
/*
* File: pcidriver.c
*
* Purpose: PCI bus access
*/
#if !defined(__PLATFORM_H__)
#include "platform.h"
#endif
#if !defined(__PCIDRIVER_H__)
#include "pcidriver.h"
#endif
/*--------------------- Static Definitions ------------------------*/
/*--------------------- Static Types ------------------------------*/
/*--------------------- Static Macros -----------------------------*/
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
/*--------------------- Static Functions --------------------------*/
static UINT32 s_u32MakeBfd2CfgAddr(UINT32 bus, UINT32 device, UINT32 function, UINT32 offset);
/*--------------------- Export Variables --------------------------*/
void PCIBDG_Initialize(void)
{
// use internal arbitor, should do this before PCICON_CONFIG_DONE had been set
ASIC_PCI_PCICON |= PCIARBITOR_INT;
// Internal Clock, PCI Reset, Pull-up,
// Enable PCI Clock output for the Slot3
ASIC_PCI_PCIDIAG0 &= ~(PCICLK_EXT | PCICLK_DC3 | PCIRESET_EXT | PCIPULLUP_EXT);
// set PCI logic & bus clock
ASIC_PCI_PCIRCC |= PCICLK_33M;
// turn off mask, will assert PCI host logic & bus reset
ASIC_PCI_PCIRCC &= ~PCIRESETCLK_MASK;
// delay for PCI bus reset
PLAT_vDelayLoop(1);
// Deassert PCI host logic & bus reset
ASIC_PCI_PCIRCC |= PCILOG_RESET;
ASIC_PCI_PCIRCC |= PCIBUS_RESET;
// to wait for exerciser to ready
PLAT_vDelayLoop(10);
// for PCI address translate to AHB address when device is in master mode
// Space(0x0 to 0x0100_0000-1), 16MB
ASIC_PCI_PCIBAM0 = (~ASIC_DRAM_SIZE) + 1;
ASIC_PCI_PCIBATPA0 = 0;
ASIC_PCI_PCIHSC |= PCI_PCIHSC_BME | PCI_PCIHSC_MWI | PCI_PCIHSC_PEE;
// Memory base address register 0/1 and IO for ARM9 use
ASIC_PCI_PCIHBAR0 = 0;
ASIC_PCI_PCIHBAR1 = 0x00080000;
ASIC_PCI_PCIHBAR2 = 0;
ASIC_PCI_PCIHSC |= PCIHSC_STATUS_ALL;
ASIC_PCI_PCICON |= PCICON_CONFIG_DONE | PCICON_SYSTEMREAD_READY;
ASIC_PCI_PCICON &= ~PCICON_MMP; //Memory Burst Read Disable(Burst Read decrease its performance).
// disable doorbell bit
ASIC_PCI_PCIBELPA &= 0x7FFFFFFF;
#if defined(__BIG_ENDIAN)
ASIC_PCI_PCISWAP |= (PCISWAP_TRW | PCISWAP_TTW); //4-byte swap
#endif
}
UINT8 PCICFG_Read8(UINT32 bus, UINT32 device, UINT32 function, UINT32 offset)
{
UINT8* pAddress;
/* generate the address of correct configuration space */
pAddress = (UINT8*) (s_u32MakeBfd2CfgAddr(bus, device, function, offset));
return (*pAddress);
}
UINT16 PCICFG_Read16(UINT32 bus, UINT32 device, UINT32 function, UINT32 offset)
{
UINT16* pAddress;
/* generate the address of correct configuration space */
pAddress = (UINT16*) (s_u32MakeBfd2CfgAddr(bus, device, function, offset));
/* now that we have valid params, go read the config space data */
return (*pAddress);
}
UINT32 PCICFG_Read32(UINT32 bus, UINT32 device, UINT32 function, UINT32 offset)
{
UINT32* pAddress;
/* generate the address of correct configuration space */
pAddress = (UINT32*) (s_u32MakeBfd2CfgAddr(bus, device, function, offset));
return (*pAddress);
}
void PCICFG_Write8(UINT32 bus, UINT32 device, UINT32 function, UINT32 offset, UINT32 data)
{
UINT8* pAddress;
/* generate the address of correct configuration space */
pAddress = (UINT8*) (s_u32MakeBfd2CfgAddr(bus, device, function, offset));
*pAddress = (UINT8)data;
}
void PCICFG_Write16(UINT32 bus, UINT32 device, UINT32 function, UINT32 offset, UINT32 data)
{
UINT16* pAddress;
/* generate the address of correct configuration space */
pAddress = (UINT16*) (s_u32MakeBfd2CfgAddr(bus, device, function, offset));
*pAddress = (UINT16)data;
}
void PCICFG_Write32(UINT32 bus, UINT32 device, UINT32 function, UINT32 offset, UINT32 data)
{
UINT32* pAddress;
/* generate the address of correct configuration space */
pAddress = (UINT32*) (s_u32MakeBfd2CfgAddr(bus, device, function, offset));
*pAddress = (UINT32)data;
}
/*============================================================================
*
* parameters: bus = which bus
* device = which device
* function = which function
* offset = configuration space register we are interested in
*
* description: this routine will generate a platform dependant config
* address.
*
* calls: none
*
* returns: configuration address to play on the PCI bus
*
* To generate the appropriate PCI configuration cycles in the PCI
* configuration address space, you make AHB address with the following pattern
*
* PCI configuration cycles look like this:
*
* Type 0: area0: 0x28000000 - 0x2800A7FF, Other space,0x2800A800 - 0x29FFFFFF, are not used
* area1: 0x38000000 - 0x3800A7FF --> Not used
*
* 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
* 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* 31:28 Area selection : 0010b(PCI space area0)
* 27:25 Access space : 100b(Type0)
* 24:16 fixed : 0 (fixed by 0)
* 15:11 Device select : 00000b(AD[11]),00001b(AD[12]),00010b(AD[13]), ... ,10100b(AD[31])
* 10:8 Function number :
* 7:2 Register number
*
* Type 1: area0: 0x2A000000 - 0x2AFFFFFF, Other space,0x2B000000 - 0x2BFFFFFF, are not used
* area1: 0x3A000000 - 0x3BFFFFFF --> Not used
*
* 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
* 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* 31:28 Area selection : 0010b(PCI space area0), 0011b(PCI space area1)
* 27:25 Access space : 101b(Type1)
* 24 fixed : 0
* 23:16 bus number (8 bits = 128 possible buses)
* 15:11 Device number (5 bits)
* 10:8 function number
* 7:2 register number
*
*/
static UINT32 s_u32MakeBfd2CfgAddr(UINT32 bus, UINT32 device, UINT32 function, UINT32 offset)
{
UINT32 address;
if (bus == 0) {
if (device != 0) {
/* Bus0, so it needs a type 0 config cycle */
/* build the PCI configuration "address" with one-hot in A31-A11 */
address = AHB_2_PCI_CFG0(device, function, offset);
}
else {
address = 0xf0110000;
address |= offset & 0xff;
}
}
else { /* bus !=0 */
/* Not Bus0, so need a type 1 config cycle */
/* A31-A24 are don't care (so clear to 0) */
address = AHB_2_PCI_CFG1(bus, device, function, offset);
}
return address;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?