📄 pcilib.c
字号:
if (val < align)
return align;
// ...finally, if there is need to move the value upwards, do so...
if ((val & ~(align - 1)) != 0)
return (((val) + ((align) - 1)) & ~((align) - 1));
else
return val;
}
/*============================================================================
*
* description: Allocate space in PCI IO memory
*
* returns: Where in PCI memory allocated
*
* Note: Calling this code has a side effect of moving the global
* IO base on.
*/
UINT32 PCIir_AllocateIOSpace (UINT32 size)
{
UINT32 alignto;
UINT32 base;
// align in minimum sized chunks of DEFAULT_IO_ALIGNMENT
alignto = MAX (size, DEFAULT_IO_ALIGNMENT);
base = ALIGN (g_u32PciIoBase, alignto);
g_u32PciIoBase = base + size;
return base;
}
/*============================================================================
*
* description: Allocate space in PCI memory
*
* returns: Where in PCI memory allocated
*
* Note: Calling this code has a side effect of moving the global
* Memory base on.
*/
static UINT32 PCIir_AllocateMemSpace (UINT32 size)
{
UINT32 alignto;
UINT32 base;
// align in minimum sized chunks of DEFAULT_MEMORY_ALIGNMENT
alignto = MAX (size, DEFAULT_MEMORY_ALIGNMENT);
base = ALIGN (g_u32PciMemBase, alignto);
g_u32PciMemBase = base + size;
return base;
}
/*============================================================================
*
* description: this routine will attempt to glean resource requirements
* from the device pointed to by handle
*
* returns: void
*/
void PCIir_AssignResources (PCIDevice_t * device)
{
UINT32 base, mask, size;
int i;
UINT32 barFlag = 0;
UINT32 slot,offset, func, bus, PciCommandData,PciVendorID;
UINT16 RomDataAtZero=0;
/* set up the bus, slot and func */
bus = device->bus;
slot = device->slot;
func = device->func;
/* Disable PCI IO and memory accesses */
PciCommandData = ((~0x3)&PCICFG_Read16(bus, slot, func, PCIHCMD_OFF));
PCICFG_Write16 (bus, slot, func, PCIHCMD_OFF, PciCommandData);
/* allocate an irq number */
if (slot!=0)
PCIir_AllocateInterrupt (device);
offset = PCIHBAR0_OFF;
/* Scan each of the BARS for this device */
for (i = 0; i < PCI_MAX_BAR; i++)
{
/* write PCI_INVALID to BAR to get size, then read it back */
PCICFG_Write32 (bus, slot, func, offset, PCI_INVALID);
base = PCICFG_Read32 (bus, slot, func, offset);
/* check if this is an implemented BAR (size != 0) */
if (base != 0)
{
/* Assign some PCI memory (IO or Memory) space to this BAR */
if (base & PCI_IO_ENABLE)
{
/* ******************** IO space BAR ******************** */
/* The bottom 2 bits of the BAR for PCI IO look like this:
0 must be 1 (0 = memory, 1 = IO)
1 reserved */
/* figure out how much memory is wanted */
base &= ~0x3;
mask = (~base << 1) | 0x1;
size = (mask & base) & 0xFFFFFFFF;
Print("\nslot[%2x], func[%x], iosize[%8x]", slot, func, size);
/* allocate (aligned) space in IO */
base = PCIir_AllocateIOSpace (size);
PCICFG_Write32 (bus, slot, func, offset, base | 0x1);
barFlag |= PCI_IO_ENABLE;
PciVendorID = PCICFG_Read16(bus,slot, func, PCIHVID_OFF);
}
else// if (base & PCI_IO_ENABLE)
{
/* ******************** MEM space BAR ******************** */
/* WARNING: I assume only one type of memory - dangerous! */
UINT32 type;
/* The bottom 4 bits of the BAR for PCI memory look like this:
0 must be zero (0 = memory, 1 = IO)
1:2 type of space needed
(00 = 32 bit, 01 = below 1M, 10 = 64 bit address)
3 prefetchable */
type = base & 0x6;
base &= (~0xf);
mask = (~base << 1) | 0x1;
size = (mask & base) & 0xFFFFFFFF;
Print("\nslot[%2x], func[%x], memsize[%8x]", slot, func, size);
/* cope (or rather don't) with different flavours of memory */
switch (type)
{
case 0x00: /* 32 bit */
break;
case 0x02: /* below 1M */
continue;
case 0x04: /* 64 bit */
offset += 4;
continue;
default:
continue;
}
/* allocate some (aligned) space in PCI memory */
base = PCIir_AllocateMemSpace (size);
PCICFG_Write32 (bus, slot, func, offset, base);
barFlag |= PCI_MEM_ENABLE;
}
} //end (base != 0)
/* increment the BAR offset value */
offset += 4;
}
/* now do the ROM stuff */
//To Prevent the enabling of the ROM address decoder
//??PCIHEXPR_OFF
PCICFG_Write32 (bus, slot, func, PCIHEXPR_OFF, (PCI_INVALID&0xfffffffe));
base = PCICFG_Read32 (bus, slot, func, PCIHEXPR_OFF);
if (base & ~PCI_EXP_ROM_ENABLE)
{
// valid ROM space, figure out how much it wants/needs
base &= ~PCI_EXP_ROM_ENABLE;
size = (~base + 1);
Print("\nslot=%2x, romsize=%8x\n", slot, size);
// Allocate some (aligned) memory space
base = PCIir_AllocateMemSpace (size);
// Let the device see it, but don't enable accesses.
// This is because, according to the specification,
// the device may share an address decoder between
// the Expansion ROM base and other base address
// registers. In other words, any device driver wishing
// to access the ROM must set the enable bit (bit 0) before
// proceeding and clear it afterwards.
PCICFG_Write32 (bus, slot, func, PCIHEXPR_OFF, base + PCI_EXP_ROM_ENABLE);
// ROM gets added to PCI memory, so allow accesses
barFlag |= PCI_MEM_ENABLE;
RomDataAtZero = *(UINT16 *)AHB_2_PCI_MEM(base);
if (RomDataAtZero== EXPROM_INSERTED)
{
;
/*======================================================
- A code image must be copied into system DRAM and its initialization code must
be executed.
- In a PC environment, the ROM code image must be copied into RAM Address :
0x000C_0000 ~ 0x000D_FFFF.
- If the class code indiacate this is VGA device's ROM, its code image must be copied
into memory starting at location 0x000C_0000
=======================================================*/
}
}
/* Enable PCI IO and memory accesses as found by scan, with MASTER */
barFlag |= PCI_MASTER_ENABLE;
PCICFG_Write16 (bus, slot, func, PCIHCMD_OFF, (PciCommandData|barFlag));
PCICFG_Write8 (bus, slot, func, PCIHCMD_OFF, 0xFF);
//Disable the ROM Address Decoder.
PCICFG_Write32 (bus, slot, func, PCIHEXPR_OFF, ~PCI_EXP_ROM_ENABLE);
}
/*============================================================================
*
* description: Allocate an interrupt #
*
* returns: void
*
*/
void PCIir_AllocateInterrupt (PCIDevice_t * device)
{
PCIDevice_t *curr;
UINT8 pin;
UINT8 interrupt;
// read the interrupt pin from the device
pin = PCICFG_Read8 (device->bus, device->slot, device->func, PCIHINTPIN_OFF);
// figure out the interrupt number
if (device->bus == 0)
{
// Primary bus
// pin is this device's pin
// curr is this device
curr = device;
}
else
{
// Secondary bus or beyond
curr = device;
while (curr->bus != 0)
{
// swizzle the interrupt pins through each PCI-PCI bridge
pin = bridgeSwizzle (pin, curr->slot);
curr = curr->parent;
}
// pin is now the pin of the last bridge
// curr is the last PCI-PCI bridge
}
// work out the interrupt number from the slot/pin
// ??
interrupt = PCIMapInterrupt(pin, curr->slot);
// write it to the device (this will be read later by a device driver)
PCICFG_Write8(device->bus, device->slot, device->func, PCIHINTLINE_OFF, interrupt);
}
/*============================================================================
*
* A small note about bridges and interrupts. The DECchip 21050 (and later chips)
* adheres to the PCI-PCI bridge specification. This says that the interrupts on
* the other side of a bridge are swizzled in the following manner:
*
* Dev Interrupt Interrupt
* Pin on Pin on
* Device Connector
*
* 4 A A
* B B
* C C
* D D
*
* 5 A B
* B C
* C D
* D A
*
* 6 A C
* B D
* C A
* D B
*
* 7 A D
* B A
* C B
* D C
*
* Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
* Thus, each swizzle is ((pin-1) + (device#-4)) % 4
*
*/
UINT8 bridgeSwizzle (UINT8 pin, UINT32 slot)
{
return (((pin - 1) + slot) % 4) + 1;
}
/*============================================================================
*
* parameters: bus = which pin (A=1, B=2, C=3, D=4)
* slot = which slot (IDSEL = slot + 11)
*
* description: this routine returns the interrupt # that this slot/pin
* combination will use.
* S3C2510X have only one PCI interrupt input pin(PCI_nINTA),
* so we may not use interrupt mapping.
* But for further system or controller,we prepare this routine.
*
* calls: none
*
* returns: Board specific interrupt #
*
*/
UINT8 PCIMapInterrupt(UINT8 pin, UINT8 slot)
{
static const UINT8 s_u8IrqTab[21][4] = {
// INTA INTB INTC INTD
{INTA, INTB, INTC, INTD}, // idsel 11, slot 0
{INTB, INTC, INTD, INTA}, // idsel 12, slot 1
{INTC, INTD, INTA, INTB}, // idsel 13, slot 2
{INTD, INTA, INTB, INTC}, // idsel 14, slot 3
{INTA, INTB, INTC, INTD}, // idsel 15, slot 4
{INTB, INTC, INTD, INTA}, // idsel 16, slot 5
{INTC, INTD, INTA, INTB}, // idsel 17, slot 6
{INTD, INTA, INTB, INTC}, // idsel 18, slot 7
{INTA, INTB, INTC, INTD}, // idsel 19, slot 8
{INTB, INTC, INTD, INTA}, // idsel 20, slot 9
{INTC, INTD, INTA, INTB}, // idsel 21, slot 10
{INTD, INTA, INTB, INTC}, // idsel 22, slot 11
{INTA, INTB, INTC, INTD}, // idsel 23, slot 12
{INTB, INTC, INTD, INTA}, // idsel 24, slot 13
{INTC, INTD, INTA, INTB}, // idsel 25, slot 14
{INTD, INTA, INTB, INTC}, // idsel 26, slot 15
{INTA, INTB, INTC, INTD}, // idsel 27, slot 16
{INTB, INTC, INTD, INTA}, // idsel 28, slot 17
{INTC, INTD, INTA, INTB}, // idsel 29, slot 18
{INTD, INTA, INTB, INTC}, // idsel 30, slot 19
{INTA, INTB, INTC, INTD} // idsel 31, slot 20
};
// if PIN = 0, default to A ,Pin=0 means ,this devices dose not use interrupt pin
if (pin == 0)
pin = 1;
// return the magic number
return s_u8IrqTab[slot][pin - 1];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -