|
@@ -59,6 +59,12 @@
|
|
|
#define SZ_1T (SZ_1G*1024ULL)
|
|
|
#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe)
|
|
|
|
|
|
+#define ROOT_CAP_AND_CTRL 0x5C
|
|
|
+
|
|
|
+/* PCIe IP version */
|
|
|
+#define XGENE_PCIE_IP_VER_UNKN 0
|
|
|
+#define XGENE_PCIE_IP_VER_1 1
|
|
|
+
|
|
|
struct xgene_pcie_port {
|
|
|
struct device_node *node;
|
|
|
struct device *dev;
|
|
@@ -67,6 +73,7 @@ struct xgene_pcie_port {
|
|
|
void __iomem *cfg_base;
|
|
|
unsigned long cfg_addr;
|
|
|
bool link_up;
|
|
|
+ u32 version;
|
|
|
};
|
|
|
|
|
|
static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
|
|
@@ -140,9 +147,37 @@ static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
|
|
|
return xgene_pcie_get_cfg_base(bus) + offset;
|
|
|
}
|
|
|
|
|
|
+static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
|
|
|
+ int where, int size, u32 *val)
|
|
|
+{
|
|
|
+ struct xgene_pcie_port *port = bus->sysdata;
|
|
|
+
|
|
|
+ if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) !=
|
|
|
+ PCIBIOS_SUCCESSFUL)
|
|
|
+ return PCIBIOS_DEVICE_NOT_FOUND;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The v1 controller has a bug in its Configuration Request
|
|
|
+ * Retry Status (CRS) logic: when CRS is enabled and we read the
|
|
|
+ * Vendor and Device ID of a non-existent device, the controller
|
|
|
+ * fabricates return data of 0xFFFF0001 ("device exists but is not
|
|
|
+ * ready") instead of 0xFFFFFFFF ("device does not exist"). This
|
|
|
+ * causes the PCI core to retry the read until it times out.
|
|
|
+ * Avoid this by not claiming to support CRS.
|
|
|
+ */
|
|
|
+ if (pci_is_root_bus(bus) && (port->version == XGENE_PCIE_IP_VER_1) &&
|
|
|
+ ((where & ~0x3) == ROOT_CAP_AND_CTRL))
|
|
|
+ *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
|
|
|
+
|
|
|
+ if (size <= 2)
|
|
|
+ *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
|
|
|
+
|
|
|
+ return PCIBIOS_SUCCESSFUL;
|
|
|
+}
|
|
|
+
|
|
|
static struct pci_ops xgene_pcie_ops = {
|
|
|
.map_bus = xgene_pcie_map_bus,
|
|
|
- .read = pci_generic_config_read32,
|
|
|
+ .read = xgene_pcie_config_read32,
|
|
|
.write = pci_generic_config_write32,
|
|
|
};
|
|
|
|
|
@@ -500,6 +535,10 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
|
|
|
port->node = of_node_get(pdev->dev.of_node);
|
|
|
port->dev = &pdev->dev;
|
|
|
|
|
|
+ port->version = XGENE_PCIE_IP_VER_UNKN;
|
|
|
+ if (of_device_is_compatible(port->node, "apm,xgene-pcie"))
|
|
|
+ port->version = XGENE_PCIE_IP_VER_1;
|
|
|
+
|
|
|
ret = xgene_pcie_map_reg(port, pdev);
|
|
|
if (ret)
|
|
|
return ret;
|