|
@@ -80,6 +80,21 @@
|
|
|
#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
|
|
|
#define PCIE_ATU_UPPER_TARGET 0x91C
|
|
|
|
|
|
+/*
|
|
|
+ * iATU Unroll-specific register definitions
|
|
|
+ * From 4.80 core version the address translation will be made by unroll
|
|
|
+ */
|
|
|
+#define PCIE_ATU_UNR_REGION_CTRL1 0x00
|
|
|
+#define PCIE_ATU_UNR_REGION_CTRL2 0x04
|
|
|
+#define PCIE_ATU_UNR_LOWER_BASE 0x08
|
|
|
+#define PCIE_ATU_UNR_UPPER_BASE 0x0C
|
|
|
+#define PCIE_ATU_UNR_LIMIT 0x10
|
|
|
+#define PCIE_ATU_UNR_LOWER_TARGET 0x14
|
|
|
+#define PCIE_ATU_UNR_UPPER_TARGET 0x18
|
|
|
+
|
|
|
+/* Register address builder */
|
|
|
+#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) ((0x3 << 20) | (region << 9))
|
|
|
+
|
|
|
/* PCIe Port Logic registers */
|
|
|
#define PLR_OFFSET 0x700
|
|
|
#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c)
|
|
@@ -141,6 +156,27 @@ static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
|
|
|
writel(val, pp->dbi_base + reg);
|
|
|
}
|
|
|
|
|
|
+static inline u32 dw_pcie_readl_unroll(struct pcie_port *pp, u32 index, u32 reg)
|
|
|
+{
|
|
|
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
|
|
|
+
|
|
|
+ if (pp->ops->readl_rc)
|
|
|
+ return pp->ops->readl_rc(pp, pp->dbi_base + offset + reg);
|
|
|
+
|
|
|
+ return readl(pp->dbi_base + offset + reg);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void dw_pcie_writel_unroll(struct pcie_port *pp, u32 index,
|
|
|
+ u32 val, u32 reg)
|
|
|
+{
|
|
|
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
|
|
|
+
|
|
|
+ if (pp->ops->writel_rc)
|
|
|
+ pp->ops->writel_rc(pp, val, pp->dbi_base + offset + reg);
|
|
|
+ else
|
|
|
+ writel(val, pp->dbi_base + offset + reg);
|
|
|
+}
|
|
|
+
|
|
|
static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
|
|
u32 *val)
|
|
|
{
|
|
@@ -164,23 +200,49 @@ static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
|
|
|
{
|
|
|
u32 retries, val;
|
|
|
|
|
|
- dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index,
|
|
|
- PCIE_ATU_VIEWPORT);
|
|
|
- dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr), PCIE_ATU_LOWER_BASE);
|
|
|
- dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr), PCIE_ATU_UPPER_BASE);
|
|
|
- dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1),
|
|
|
- PCIE_ATU_LIMIT);
|
|
|
- dw_pcie_writel_rc(pp, lower_32_bits(pci_addr), PCIE_ATU_LOWER_TARGET);
|
|
|
- dw_pcie_writel_rc(pp, upper_32_bits(pci_addr), PCIE_ATU_UPPER_TARGET);
|
|
|
- dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1);
|
|
|
- dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
|
|
+ if (pp->iatu_unroll_enabled) {
|
|
|
+ dw_pcie_writel_unroll(pp, index,
|
|
|
+ lower_32_bits(cpu_addr), PCIE_ATU_UNR_LOWER_BASE);
|
|
|
+ dw_pcie_writel_unroll(pp, index,
|
|
|
+ upper_32_bits(cpu_addr), PCIE_ATU_UNR_UPPER_BASE);
|
|
|
+ dw_pcie_writel_unroll(pp, index,
|
|
|
+ lower_32_bits(cpu_addr + size - 1), PCIE_ATU_UNR_LIMIT);
|
|
|
+ dw_pcie_writel_unroll(pp, index,
|
|
|
+ lower_32_bits(pci_addr), PCIE_ATU_UNR_LOWER_TARGET);
|
|
|
+ dw_pcie_writel_unroll(pp, index,
|
|
|
+ upper_32_bits(pci_addr), PCIE_ATU_UNR_UPPER_TARGET);
|
|
|
+ dw_pcie_writel_unroll(pp, index,
|
|
|
+ type, PCIE_ATU_UNR_REGION_CTRL1);
|
|
|
+ dw_pcie_writel_unroll(pp, index,
|
|
|
+ PCIE_ATU_ENABLE, PCIE_ATU_UNR_REGION_CTRL2);
|
|
|
+ } else {
|
|
|
+ dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | index,
|
|
|
+ PCIE_ATU_VIEWPORT);
|
|
|
+ dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr),
|
|
|
+ PCIE_ATU_LOWER_BASE);
|
|
|
+ dw_pcie_writel_rc(pp, upper_32_bits(cpu_addr),
|
|
|
+ PCIE_ATU_UPPER_BASE);
|
|
|
+ dw_pcie_writel_rc(pp, lower_32_bits(cpu_addr + size - 1),
|
|
|
+ PCIE_ATU_LIMIT);
|
|
|
+ dw_pcie_writel_rc(pp, lower_32_bits(pci_addr),
|
|
|
+ PCIE_ATU_LOWER_TARGET);
|
|
|
+ dw_pcie_writel_rc(pp, upper_32_bits(pci_addr),
|
|
|
+ PCIE_ATU_UPPER_TARGET);
|
|
|
+ dw_pcie_writel_rc(pp, type, PCIE_ATU_CR1);
|
|
|
+ dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* Make sure ATU enable takes effect before any subsequent config
|
|
|
* and I/O accesses.
|
|
|
*/
|
|
|
for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
|
|
|
- val = dw_pcie_readl_rc(pp, PCIE_ATU_CR2);
|
|
|
+ if (pp->iatu_unroll_enabled)
|
|
|
+ val = dw_pcie_readl_unroll(pp, index,
|
|
|
+ PCIE_ATU_UNR_REGION_CTRL2);
|
|
|
+ else
|
|
|
+ val = dw_pcie_readl_rc(pp, PCIE_ATU_CR2);
|
|
|
+
|
|
|
if (val == PCIE_ATU_ENABLE)
|
|
|
return;
|
|
|
|
|
@@ -445,6 +507,17 @@ static const struct irq_domain_ops msi_domain_ops = {
|
|
|
.map = dw_pcie_msi_map,
|
|
|
};
|
|
|
|
|
|
+static u8 dw_pcie_iatu_unroll_enabled(struct pcie_port *pp)
|
|
|
+{
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ val = dw_pcie_readl_rc(pp, PCIE_ATU_VIEWPORT);
|
|
|
+ if (val == 0xffffffff)
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int dw_pcie_host_init(struct pcie_port *pp)
|
|
|
{
|
|
|
struct device_node *np = pp->dev->of_node;
|
|
@@ -561,6 +634,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ pp->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pp);
|
|
|
+
|
|
|
if (pp->ops->host_init)
|
|
|
pp->ops->host_init(pp);
|
|
|
|