|
@@ -85,6 +85,8 @@
|
|
|
#define IMAP_VALID_SHIFT 0
|
|
|
#define IMAP_VALID BIT(IMAP_VALID_SHIFT)
|
|
|
|
|
|
+#define IPROC_PCI_PM_CAP 0x48
|
|
|
+#define IPROC_PCI_PM_CAP_MASK 0xffff
|
|
|
#define IPROC_PCI_EXP_CAP 0xac
|
|
|
|
|
|
#define IPROC_PCIE_REG_INVALID 0xffff
|
|
@@ -375,6 +377,17 @@ static const u16 iproc_pcie_reg_paxc_v2[] = {
|
|
|
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * List of device IDs of controllers that have corrupted capability list that
|
|
|
+ * require SW fixup
|
|
|
+ */
|
|
|
+static const u16 iproc_pcie_corrupt_cap_did[] = {
|
|
|
+ 0x16cd,
|
|
|
+ 0x16f0,
|
|
|
+ 0xd802,
|
|
|
+ 0xd804
|
|
|
+};
|
|
|
+
|
|
|
static inline struct iproc_pcie *iproc_data(struct pci_bus *bus)
|
|
|
{
|
|
|
struct iproc_pcie *pcie = bus->sysdata;
|
|
@@ -495,6 +508,49 @@ static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p)
|
|
|
return data;
|
|
|
}
|
|
|
|
|
|
+static void iproc_pcie_fix_cap(struct iproc_pcie *pcie, int where, u32 *val)
|
|
|
+{
|
|
|
+ u32 i, dev_id;
|
|
|
+
|
|
|
+ switch (where & ~0x3) {
|
|
|
+ case PCI_VENDOR_ID:
|
|
|
+ dev_id = *val >> 16;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Activate fixup for those controllers that have corrupted
|
|
|
+ * capability list registers
|
|
|
+ */
|
|
|
+ for (i = 0; i < ARRAY_SIZE(iproc_pcie_corrupt_cap_did); i++)
|
|
|
+ if (dev_id == iproc_pcie_corrupt_cap_did[i])
|
|
|
+ pcie->fix_paxc_cap = true;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IPROC_PCI_PM_CAP:
|
|
|
+ if (pcie->fix_paxc_cap) {
|
|
|
+ /* advertise PM, force next capability to PCIe */
|
|
|
+ *val &= ~IPROC_PCI_PM_CAP_MASK;
|
|
|
+ *val |= IPROC_PCI_EXP_CAP << 8 | PCI_CAP_ID_PM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IPROC_PCI_EXP_CAP:
|
|
|
+ if (pcie->fix_paxc_cap) {
|
|
|
+ /* advertise root port, version 2, terminate here */
|
|
|
+ *val = (PCI_EXP_TYPE_ROOT_PORT << 4 | 2) << 16 |
|
|
|
+ PCI_CAP_ID_EXP;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IPROC_PCI_EXP_CAP + PCI_EXP_RTCTL:
|
|
|
+ /* Don't advertise CRS SV support */
|
|
|
+ *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
|
|
int where, int size, u32 *val)
|
|
|
{
|
|
@@ -509,13 +565,10 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
|
|
/* root complex access */
|
|
|
if (busno == 0) {
|
|
|
ret = pci_generic_config_read32(bus, devfn, where, size, val);
|
|
|
- if (ret != PCIBIOS_SUCCESSFUL)
|
|
|
- return ret;
|
|
|
+ if (ret == PCIBIOS_SUCCESSFUL)
|
|
|
+ iproc_pcie_fix_cap(pcie, where, val);
|
|
|
|
|
|
- /* Don't advertise CRS SV support */
|
|
|
- if ((where & ~0x3) == IPROC_PCI_EXP_CAP + PCI_EXP_RTCTL)
|
|
|
- *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
|
|
|
- return PCIBIOS_SUCCESSFUL;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where);
|