Here is my initialization code
Code: Select all
static void writeField(ulong addr, u32 mask, unsigned shift, u32 val)
{
u32 tmp = CPU::MMIORead32(addr);
tmp &= ~mask;
tmp |= (val << shift) & mask;
CPU::MMIOWrite32(addr, val);
}
static void setGen(unsigned gen)
{
u32 lnkcap = CPU::MMIORead32(pcieBase + CAP_REGS + PCI_EXP_LNKCAP);
u16 lnkctl2 = CPU::MMIORead16(pcieBase + CAP_REGS + PCI_EXP_LNKCTL2);
lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen;
CPU::MMIOWrite32(pcieBase + CAP_REGS + PCI_EXP_LNKCAP, lnkcap);
lnkctl2 = (lnkctl2 & ~0xFu) | static_cast<u16>(gen);
CPU::MMIOWrite16(pcieBase + CAP_REGS + PCI_EXP_LNKCTL2, lnkctl2);
}
static inline unsigned makeIdx(unsigned bus, unsigned dev, unsigned fun)
{
bus &= BUS_MASK; dev &= DEV_MASK; fun &= FUN_MASK;
return bus << 20 | dev << 15 | fun << 12;
}
errcode PCI::Initialize()
{
errcode stat = ESUCCESS;
pcieBase = Paging::MapMMIO(&stat, PCIE_BASE, PCIE_SIZE);
if(stat != ESUCCESS)
{
pcieBase = 0;
return stat;
}
// assert bridge reset
writeField(pcieBase + RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK, RGR1_SW_INIT_1_INIT_SHIFT, 1);
Time::Sleep(1, false);
// assert fundamental reset
writeField(pcieBase + RGR1_SW_INIT_1, RGR1_SW_INIT_1_PERST_MASK, RGR1_SW_INIT_1_PERST_SHIFT, 1);
Time::Sleep(1, false);
// deassert bridge reset
writeField(pcieBase + RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK, RGR1_SW_INIT_1_INIT_SHIFT, 0);
Time::Sleep(1, false);
// enable serdes
writeField(pcieBase + HARD_PCIE_HARD_DEBUG, HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK,
HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_SHIFT, 0);
Time::Sleep(1, false);
// get hardware revision
hwRev = CPU::MMIORead32(pcieBase + PCIE_REVISION) & 0xFFFFu;
// disable and clear any pending interrupts
CPU::MMIOWrite32(pcieBase + MSI_INTR2_BASE + INTR_CLR, 0xFFFFFFFFu);
CPU::MMIOWrite32(pcieBase + MSI_INTR2_BASE + INTR_MASK_SET, 0xFFFFFFFFu);
// what does this exactly do ???
CPU::MMIOWrite32(pcieBase + CPU_2_PCIE_MEM_WIN0_LO, 0);
CPU::MMIOWrite32(pcieBase + CPU_2_PCIE_MEM_WIN0_HI, 0);
CPU::MMIOWrite32(pcieBase + CPU_2_PCIE_MEM_WIN0_BASE_LIMIT, 0);
CPU::MMIOWrite32(pcieBase + CPU_2_PCIE_MEM_WIN0_BASE_HI, 0);
CPU::MMIOWrite32(pcieBase + CPU_2_PCIE_MEM_WIN0_LIMIT_HI, 0);
// initialize SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN and CTRL_SCB0_SIZE
CPU::MMIOWrite32(pcieBase + MISC_CTRL,
CTRL_SCB0_SIZE(LOG2DMASIZE - 15) |
MAX_BURST_SIZE(BURST_SIZE_128) |
CFG_READ_UR_MODE(1) |
SCB_ACCESS_EN(1));
// setup inbound memory view
CPU::MMIOWrite32(pcieBase + RC_BAR2_CONFIG_LO, (LOG2DMASIZE - 15));
CPU::MMIOWrite32(pcieBase + RC_BAR2_CONFIG_HI, 0);
// disable PCIe->GISB and PCIe->SCB
CPU::MMIOWrite32(pcieBase + RC_BAR1_CONFIG_LO, 0);
CPU::MMIOWrite32(pcieBase + RC_BAR3_CONFIG_LO, 0);
// setup MSIs
CPU::MMIOWrite32(pcieBase + MSI_BAR_CONFIG_LO, (MSI_TARGET_ADDR & 0xFFFFFFFFu) | 1);
CPU::MMIOWrite32(pcieBase + MSI_BAR_CONFIG_HI, MSI_TARGET_ADDR >> 32);
CPU::MMIOWrite32(pcieBase + MSI_DATA_CONFIG, hwRev >= HW_REV_33 ? 0xffe06540 : 0xFFF86540);
// TODO: add MSI handler registration here
// cap controller to Gen2
setGen(2);
// deassert fundamental reset
writeField(pcieBase + RGR1_SW_INIT_1, RGR1_SW_INIT_1_PERST_MASK, RGR1_SW_INIT_1_PERST_SHIFT, 0);
for(unsigned int i = 0; i < 10; ++i)
{
if((CPU::MMIORead32(pcieBase + PCIE_STATUS) & 0x30) == 0x30)
break;
Time::Sleep(100, false);
}
// check if link is up
if((CPU::MMIORead32(pcieBase + PCIE_STATUS) & 0x30) != 0x30)
{
Debug::PutFmt("PCIe link is down\n");
return EERROR;
}
Debug::PutFmt("PCIe link is up\n");
// check if controller is running in root complex mode
if((CPU::MMIORead32(pcieBase + PCIE_STATUS) & 0x80) != 0x80)
{
Debug::PutFmt("PCIe controller is not running in root complex mode\n");
return EERROR;
}
// set proper class Id
CPU::MMIOWrite32(pcieBase + RC_CFG_PRIV1_ID_VAL3, 0x060400);
// set proper endian
writeField(pcieBase + RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK,
RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_SHIFT,
DATA_ENDIAN);
// set debug mode
writeField(pcieBase + HARD_PCIE_HARD_DEBUG, HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK,
HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_SHIFT, 1);
return ESUCCESS;
}
I also don't fully understand used terminology either. What is MDIO, GISB, SCB, inbound and outbound memory?
And here is how I access configuration space
Code: Select all
u32 PCI::ConfigRead32(unsigned bus, unsigned dev, unsigned fun, unsigned reg)
{
cfgLock.Lock();
u32 res = 0;
if(!bus && !dev)
res = CPU::MMIORead32(pcieBase + reg);
else
{
CPU::MMIOWrite32(pcieBase + EXT_CFG_INDEX, makeIdx(bus, dev, fun));
res = CPU::MMIORead32(pcieBase + EXT_CFG_DATA + reg);
}
cfgLock.Unlock();
return res;
}
void PCI::ConfigWrite32(unsigned bus, unsigned dev, unsigned fun, unsigned reg, u32 val)
{
cfgLock.Lock();
if(!bus && !dev)
CPU::MMIOWrite32(pcieBase + reg, val);
else
{
CPU::MMIOWrite32(pcieBase + EXT_CFG_INDEX, makeIdx(bus, dev, fun));
CPU::MMIOWrite32(pcieBase + EXT_CFG_DATA + reg, val);
}
cfgLock.Unlock();
}