diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 947fac37cf1b79..44c63fb6b1cf33 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -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); diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index 285e1edc505bed..e74cc4a93fb98d 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -48,6 +48,7 @@ struct pcie_port { int msi_irq; struct irq_domain *irq_domain; unsigned long msi_data; + u8 iatu_unroll_enabled; DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); };