@@ -85,27 +85,42 @@
#define IMSI_ADDR 0x190
#define ISTATUS_MSI 0x194
+#define ATR_WINDOW_DESC_SIZE 32
+#define ATR_PCIE_ATR_SIZE 0x25
+#define ATR_SIZE_SHIFT 1
+#define ATR_IMPL_ENABLE 1
+
/* PCIe Master table init defines */
#define ATR0_PCIE_WIN0_SRCADDR_PARAM 0x600u
-#define ATR0_PCIE_ATR_SIZE 0x25
-#define ATR0_PCIE_ATR_SIZE_SHIFT 1
#define ATR0_PCIE_WIN0_SRC_ADDR 0x604u
#define ATR0_PCIE_WIN0_TRSL_ADDR_LSB 0x608u
#define ATR0_PCIE_WIN0_TRSL_ADDR_UDW 0x60cu
#define ATR0_PCIE_WIN0_TRSL_PARAM 0x610u
+enum {
+ TRSL_ID_PCIE_TXRX,
+ TRSL_ID_PCIE_CONFIG,
+ TRSL_ID_AXI4_LITE_MASTER,
+ TRSL_ID_AXI4_MASTER_0 = 4,
+ TRSL_ID_AXI4_MASTER_1,
+ TRSL_ID_AXI4_MASTER_2,
+ TRSL_ID_AXI4_MASTER_3,
+ TRSL_ID_AXI4_STREAM_0,
+ TRSL_ID_AXI4_STREAM_1,
+ TRSL_ID_AXI4_STREAM_2,
+ TRSL_ID_AXI4_STREAM_3,
+ TRSL_ID_INTERNAL_BRIDGE_REGISTERS
+};
+
+#define ATR0_PCIE_WIN0_TRSL_MASK_LSB 0x618u
+#define ATR0_PCIE_WIN0_TRSL_MASK_UDW 0x61cu
+
/* PCIe AXI slave table init defines */
#define ATR0_AXI4_SLV0_SRCADDR_PARAM 0x800u
-#define ATR_SIZE_SHIFT 1
-#define ATR_IMPL_ENABLE 1
#define ATR0_AXI4_SLV0_SRC_ADDR 0x804u
#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB 0x808u
#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW 0x80cu
#define ATR0_AXI4_SLV0_TRSL_PARAM 0x810u
-#define PCIE_TX_RX_INTERFACE 0x00000000u
-#define PCIE_CONFIG_INTERFACE 0x00000001u
-
-#define ATR_ENTRY_SIZE 32
/* PCIe Controller Phy Regs */
#define SEC_ERROR_EVENT_CNT 0x20
@@ -270,6 +285,7 @@ struct mc_pcie {
struct irq_domain *event_domain;
raw_spinlock_t lock;
struct mc_msi msi;
+ u64 outbound_range_offset;
};
struct cause {
@@ -930,36 +946,36 @@ static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
phys_addr_t axi_addr, phys_addr_t pci_addr,
size_t size)
{
- u32 atr_sz = ilog2(size) - 1;
+ u32 atr_size = ilog2(size) - 1;
u32 val;
if (index == 0)
- val = PCIE_CONFIG_INTERFACE;
+ val = TRSL_ID_PCIE_CONFIG;
else
- val = PCIE_TX_RX_INTERFACE;
+ val = TRSL_ID_PCIE_TXRX;
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ writel(val, bridge_base_addr + (index * ATR_WINDOW_DESC_SIZE) +
ATR0_AXI4_SLV0_TRSL_PARAM);
- val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
+ val = lower_32_bits(axi_addr) | (atr_size << ATR_SIZE_SHIFT) |
ATR_IMPL_ENABLE;
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ writel(val, bridge_base_addr + (index * ATR_WINDOW_DESC_SIZE) +
ATR0_AXI4_SLV0_SRCADDR_PARAM);
val = upper_32_bits(axi_addr);
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ writel(val, bridge_base_addr + (index * ATR_WINDOW_DESC_SIZE) +
ATR0_AXI4_SLV0_SRC_ADDR);
val = lower_32_bits(pci_addr);
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ writel(val, bridge_base_addr + (index * ATR_WINDOW_DESC_SIZE) +
ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
val = upper_32_bits(pci_addr);
- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
+ writel(val, bridge_base_addr + (index * ATR_WINDOW_DESC_SIZE) +
ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
- val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
+ val |= (ATR_PCIE_ATR_SIZE << ATR_SIZE_SHIFT);
writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
}
@@ -972,14 +988,14 @@ static int mc_pcie_setup_windows(struct platform_device *pdev,
struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
struct resource_entry *entry;
u64 pci_addr;
- u32 index = 1;
+ u32 index = 1; /* Window 0 used for config space */
resource_list_for_each_entry(entry, &bridge->windows) {
if (resource_type(entry->res) == IORESOURCE_MEM) {
pci_addr = entry->res->start - entry->offset;
mc_pcie_setup_window(bridge_base_addr, index,
- entry->res->start, pci_addr,
- resource_size(entry->res));
+ entry->res->start - port->outbound_range_offset,
+ pci_addr, resource_size(entry->res));
index++;
}
}
@@ -1103,6 +1119,44 @@ static int mc_init_interrupts(struct platform_device *pdev, struct mc_pcie *port
return 0;
}
+static int mc_check_for_parent_range_handling(struct platform_device *pdev, struct mc_pcie *port)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *dn = dev->of_node;
+ struct of_range_parser parser;
+ struct of_range range;
+ u64 cpu_addr;
+
+ /* Find any pcie range */
+ if (of_range_parser_init(&parser, dn)) {
+ dev_err(dev, "missing ranges property\n");
+ return -EINVAL;
+ }
+
+ for_each_of_range(&parser, &range) {
+ cpu_addr = range.cpu_addr;
+ /*
+ * First range is enough - extend if anyone ever needs more
+ * than one fabric interface
+ */
+ break;
+ }
+
+ /* Check for one level up; that is enough */
+ dn = of_get_parent(dn);
+ if (dn) {
+ of_range_parser_init(&parser, dn);
+ for_each_of_range(&parser, &range) {
+ /* Find the parent range that contains cpu_addr */
+ if (range.cpu_addr > port->outbound_range_offset &&
+ range.cpu_addr < cpu_addr)
+ port->outbound_range_offset = range.cpu_addr;
+ }
+ }
+
+ return 0;
+}
+
static int mc_platform_init(struct pci_config_window *cfg)
{
struct device *dev = cfg->parent;
@@ -1111,9 +1165,18 @@ static int mc_platform_init(struct pci_config_window *cfg)
port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
int ret;
+ /*
+ * Need information about any parent bus that may be performing some
+ * of the outbound address translation to setup outbound address
+ * translation tables later
+ */
+ ret = mc_check_for_parent_range_handling(pdev, port);
+ if (ret)
+ return ret;
+
/* Configure address translation table 0 for PCIe config space */
- mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
- cfg->res.start,
+ mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start - port->outbound_range_offset,
+ cfg->res.start - port->outbound_range_offset,
resource_size(&cfg->res));
/* Need some fixups in config space */