static u_int32_t xlp_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) { uint32_t data = 0; uint64_t cfgaddr; int regindex = reg/sizeof(uint32_t); cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); if ((width == 2) && (reg & 1)) return 0xFFFFFFFF; else if ((width == 4) && (reg & 3)) return 0xFFFFFFFF; /* * The intline and int pin of SoC devices are DOA, except * for bridges (slot %8 == 1). * use the values we stashed in a writable PCI scratch reg. */ if (b == 0 && regindex == 0xf && s % 8 > 1) regindex = XLP_PCI_DEVSCRATCH_REG0; data = nlm_read_pci_reg(cfgaddr, regindex); if (width == 1) return ((data >> ((reg & 3) << 3)) & 0xff); else if (width == 2)
static u_int32_t xlp_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) { uint32_t data = 0; uint64_t cfgaddr; int regindex = reg/sizeof(uint32_t); cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); if ((width == 2) && (reg & 1)) return 0xFFFFFFFF; else if ((width == 4) && (reg & 3)) return 0xFFFFFFFF; data = nlm_read_pci_reg(cfgaddr, regindex); /* * Fix up read data in some SoC devices * to emulate complete PCIe header */ if (b == 0) { int dev = s % 8; /* Fake intpin on config read for UART/I2C, USB, SD/Flash */ if (regindex == 0xf && (dev == 6 || dev == 2 || dev == 7)) data |= 0x1 << 8; /* Fake int pin */ } if (width == 1) return ((data >> ((reg & 3) << 3)) & 0xff); else if (width == 2)
/* * Switch a link to MSI-X mode */ static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr) { u32 val; val = nlm_read_reg(lnkbase, 0x2C); if ((val & 0x80000000U) == 0) { val |= 0x80000000U; nlm_write_reg(lnkbase, 0x2C, val); } if (cpu_is_xlp9xx()) { val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0); if ((val & 0x200) == 0) { val |= 0x200; /* MSI Interrupt enable */ nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val); } } else { val = nlm_read_reg(lnkbase, PCIE_INT_EN0); if ((val & 0x200) == 0) { val |= 0x200; /* MSI Interrupt enable */ nlm_write_reg(lnkbase, PCIE_INT_EN0, val); } } val = nlm_read_reg(lnkbase, 0x1); /* CMD */ if ((val & 0x0400) == 0) { val |= 0x0400; nlm_write_reg(lnkbase, 0x1, val); } /* Update IRQ in the PCI irq reg */ val = nlm_read_pci_reg(lnkbase, 0xf); val &= ~0x1fu; val |= (1 << 8) | lirq; nlm_write_pci_reg(lnkbase, 0xf, val); if (cpu_is_xlp9xx()) { /* MSI-X addresses */ nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_BASE, msixaddr >> 8); nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_LIMIT, (msixaddr + MSI_ADDR_SZ) >> 8); } else {
/* * Setup a PCIe link for MSI. By default, the links are in * legacy interrupt mode. We will switch them to MSI mode * at the first MSI request. */ static void xlp_config_link_msi(uint64_t lnkbase, int lirq, uint64_t msiaddr) { u32 val; if (cpu_is_xlp9xx()) { val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0); if ((val & 0x200) == 0) { val |= 0x200; /* MSI Interrupt enable */ nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val); } } else { val = nlm_read_reg(lnkbase, PCIE_INT_EN0); if ((val & 0x200) == 0) { val |= 0x200; nlm_write_reg(lnkbase, PCIE_INT_EN0, val); } } val = nlm_read_reg(lnkbase, 0x1); /* CMD */ if ((val & 0x0400) == 0) { val |= 0x0400; nlm_write_reg(lnkbase, 0x1, val); } /* Update IRQ in the PCI irq reg */ val = nlm_read_pci_reg(lnkbase, 0xf); val &= ~0x1fu; val |= (1 << 8) | lirq; nlm_write_pci_reg(lnkbase, 0xf, val); /* MSI addr */ nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRH, msiaddr >> 32); nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRL, msiaddr & 0xffffffff); /* MSI cap for bridge */ val = nlm_read_reg(lnkbase, PCIE_BRIDGE_MSI_CAP); if ((val & (1 << 16)) == 0) { val |= 0xb << 16; /* mmc32, msi enable */ nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_CAP, val); } }