[U-Boot] [PATCH] dm: pcie: designware: add correct ATU handling

igall at marvell.com igall at marvell.com
Wed Feb 14 17:25:23 UTC 2018


From: Igal Liberman <igall at marvell.com>

Currently, ATU (address translation unit) implementation doesn't
support translate addresses > 32 bits.

This patch allows to configure ATU correctly for different
memory accesses (memory, configuration and IO).
The same approach is used in Linux Kernel.

Signed-off-by: Igal Liberman <igall at marvell.com>
---
 drivers/pci/pcie_dw_mvebu.c | 91 +++++++++++++++++++++++++++++----------------
 1 file changed, 58 insertions(+), 33 deletions(-)

diff --git a/drivers/pci/pcie_dw_mvebu.c b/drivers/pci/pcie_dw_mvebu.c
index a198855..a0032b7 100644
--- a/drivers/pci/pcie_dw_mvebu.c
+++ b/drivers/pci/pcie_dw_mvebu.c
@@ -111,6 +111,10 @@ struct pcie_dw_mvebu {
 	void *cfg_base;
 	fdt_size_t cfg_size;
 	int first_busno;
+
+	/* IO and MEM PCI regions */
+	struct pci_region io;
+	struct pci_region mem;
 };
 
 static int pcie_dw_get_link_speed(const void *regs_base)
@@ -126,6 +130,34 @@ static int pcie_dw_get_link_width(const void *regs_base)
 }
 
 /**
+ * pcie_dw_prog_outbound_atu() - Configure ATU for outbound accesses
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @index: ATU region index
+ * @type: ATU accsess type
+ * @cpu_addr: the physical address for the translation entry
+ * @pci_addr: the pcie bus address for the translation entry
+ * @size: the size of the translation entry
+ */
+static void pcie_dw_prog_outbound_atu(struct pcie_dw_mvebu *pcie, int index,
+				      int type, u64 cpu_addr, u64 pci_addr,
+				      u32 size)
+{
+	writel(PCIE_ATU_REGION_OUTBOUND | index,
+	       pcie->ctrl_base + PCIE_ATU_VIEWPORT);
+	writel(lower_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_LOWER_BASE);
+	writel(upper_32_bits(cpu_addr), pcie->ctrl_base + PCIE_ATU_UPPER_BASE);
+	writel(lower_32_bits(cpu_addr + size - 1),
+	       pcie->ctrl_base + PCIE_ATU_LIMIT);
+	writel(lower_32_bits(pci_addr),
+	       pcie->ctrl_base + PCIE_ATU_LOWER_TARGET);
+	writel(upper_32_bits(pci_addr),
+	       pcie->ctrl_base + PCIE_ATU_UPPER_TARGET);
+	writel(type, pcie->ctrl_base + PCIE_ATU_CR1);
+	writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2);
+}
+
+/**
  * set_cfg_address() - Configure the PCIe controller config space access
  *
  * @pcie: Pointer to the PCI controller state
@@ -143,27 +175,29 @@ static uintptr_t set_cfg_address(struct pcie_dw_mvebu *pcie,
 				 pci_dev_t d, uint where)
 {
 	uintptr_t va_address;
+	u32 atu_type;
 
 	/*
 	 * Region #0 is used for Outbound CFG space access.
 	 * Direction = Outbound
 	 * Region Index = 0
 	 */
-	writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT);
 
 	if (PCI_BUS(d) == (pcie->first_busno + 1))
 		/* For local bus, change TLP Type field to 4. */
-		writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1);
+		atu_type = PCIE_ATU_TYPE_CFG0;
 	else
 		/* Otherwise, change TLP Type field to 5. */
-		writel(PCIE_ATU_TYPE_CFG1, pcie->ctrl_base + PCIE_ATU_CR1);
+		atu_type = PCIE_ATU_TYPE_CFG1;
 
 	if (PCI_BUS(d) == pcie->first_busno) {
 		/* Accessing root port configuration space. */
 		va_address = (uintptr_t)pcie->ctrl_base;
 	} else {
 		d = PCI_MASK_BUS(d) | (PCI_BUS(d) - pcie->first_busno);
-		writel(d << 8, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET);
+		pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+					  atu_type, (u64)pcie->cfg_base,
+					  d << 8, pcie->cfg_size);
 		va_address = (uintptr_t)pcie->cfg_base;
 	}
 
@@ -231,6 +265,10 @@ static int pcie_dw_mvebu_read_config(struct udevice *bus, pci_dev_t bdf,
 	debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
 	*valuep = pci_conv_32_to_size(value, offset, size);
 
+	pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+				  PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+				  pcie->io.bus_start, pcie->io.size);
+
 	return 0;
 }
 
@@ -272,6 +310,10 @@ static int pcie_dw_mvebu_write_config(struct udevice *bus, pci_dev_t bdf,
 	value = pci_conv_size_to_32(old, value, offset, size);
 	writel(value, va_address);
 
+	pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+				  PCIE_ATU_TYPE_IO, pcie->io.phys_start,
+				  pcie->io.bus_start, pcie->io.size);
+
 	return 0;
 }
 
@@ -388,34 +430,6 @@ static int pcie_dw_mvebu_pcie_link_up(const void *regs_base, u32 cap_speed)
 }
 
 /**
- * pcie_dw_regions_setup() - iATU region setup
- *
- * @pcie: Pointer to the PCI controller state
- *
- * Configure the iATU regions in the PCIe controller for outbound access.
- */
-static void pcie_dw_regions_setup(struct pcie_dw_mvebu *pcie)
-{
-	/*
-	 * Region #0 is used for Outbound CFG space access.
-	 * Direction = Outbound
-	 * Region Index = 0
-	 */
-	writel(0, pcie->ctrl_base + PCIE_ATU_VIEWPORT);
-
-	writel((u32)(uintptr_t)pcie->cfg_base, pcie->ctrl_base
-	       + PCIE_ATU_LOWER_BASE);
-	writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_BASE);
-	writel((u32)(uintptr_t)pcie->cfg_base + pcie->cfg_size,
-	       pcie->ctrl_base + PCIE_ATU_LIMIT);
-
-	writel(0, pcie->ctrl_base + PCIE_ATU_LOWER_TARGET);
-	writel(0, pcie->ctrl_base + PCIE_ATU_UPPER_TARGET);
-	writel(PCIE_ATU_TYPE_CFG0, pcie->ctrl_base + PCIE_ATU_CR1);
-	writel(PCIE_ATU_ENABLE, pcie->ctrl_base + PCIE_ATU_CR2);
-}
-
-/**
  * pcie_dw_set_host_bars() - Configure the host BARs
  *
  * @regs_base: A pointer to the PCIe controller registers
@@ -495,7 +509,18 @@ static int pcie_dw_mvebu_probe(struct udevice *dev)
 		       hose->first_busno);
 	}
 
-	pcie_dw_regions_setup(pcie);
+	/* Store the IO and MEM windows settings for future use by the ATU */
+	pcie->io.phys_start = hose->regions[0].phys_start; /* IO base */
+	pcie->io.bus_start  = hose->regions[0].bus_start;  /* IO_bus_addr */
+	pcie->io.size	    = hose->regions[0].size;	   /* IO size */
+
+	pcie->mem.phys_start = hose->regions[1].phys_start; /* MEM base */
+	pcie->mem.bus_start  = hose->regions[1].bus_start;  /* MEM_bus_addr */
+	pcie->mem.size	     = hose->regions[1].size;	    /* MEM size */
+
+	pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX1,
+				  PCIE_ATU_TYPE_MEM, pcie->mem.phys_start,
+				  pcie->mem.bus_start, pcie->mem.size);
 
 	/* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
 	clrsetbits_le32(pcie->ctrl_base + PCI_CLASS_REVISION,
-- 
2.7.4



More information about the U-Boot mailing list