[PATCH 1/3] bsps/qoriq: Add MMU regions for PCIe based on fdt

Christian Mauderer christian.mauderer at embedded-brains.de
Tue Jan 23 09:08:59 UTC 2024


Get the memory ranges for the PCIe from the FDT and add them to the MMU.
This is necessary so that the PCIe driver in libbsd can work.
---
 bsps/powerpc/qoriq/start/mmu-config.c | 88 +++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/bsps/powerpc/qoriq/start/mmu-config.c b/bsps/powerpc/qoriq/start/mmu-config.c
index 58b08c8349..15e4a83fc4 100644
--- a/bsps/powerpc/qoriq/start/mmu-config.c
+++ b/bsps/powerpc/qoriq/start/mmu-config.c
@@ -305,6 +305,92 @@ static void TEXT config_fdt_adjust(const void *fdt)
 	}
 }
 
+/*
+ * Each PCIe controller has a ranges attribute in the fdt like the following:
+ *
+ *   ranges = <0x2000000 0x00 0xc0000000 0x00 0xc0000000 0x00 0x20000000
+ *             0x1000000 0x00 0x00000000 0x00 0xffc20000 0x00 0x00010000>;
+ *             |------PCI address------| |-CPU address-| |-----size----|
+ *
+ * In theory, some fdt-attributes should be used to find out how long the PCI
+ * address (#address-cells of the PCIe node), the CPU address (#address-cells of
+ * the parent node) and the size (#size-cells of the PCIe node) are. In our case
+ * the structure is fixed because the pcie root controllers are a part of the
+ * chip. Therefore the sizes will never change and we can assume fixed lengths.
+ *
+ * The first cell of the PCI address holds a number of flags. A detailed
+ * explanation can be found for example here:
+ *
+ * https://web.archive.org/web/20240109080338/https://michael2012z.medium.com/understanding-pci-node-in-fdt-769a894a13cc
+ *
+ * We are only interested in the entry with the flags 0x02000000 which basically
+ * means that it is a non-relocatable, non-prefetchable, not-aliased 32 bit
+ * memory space on the first bus.
+ *
+ * The other two cells of the PCI address are a 64 Bit address viewed from PCI
+ * address space. The two CPU address cells are the same 64 Bit address viewed
+ * from CPU address space. For our controller these two should always be the
+ * same (no address translation). The last two cells give a size of the memory
+ * region (in theory in PCI address space but it has to be the same for CPU and
+ * PCI).
+ */
+static void TEXT add_pcie_regions(qoriq_mmu_context *context, const void *fdt)
+{
+	int node;
+
+	node = -1;
+
+	while (true) {
+		static const size_t range_length = 7 * 4;
+		const void *val;
+		int len;
+
+		node = fdt_node_offset_by_compatible(
+			fdt,
+			node,
+			"fsl,mpc8548-pcie"
+		);
+		if (node < 0) {
+			break;
+		}
+
+		val = fdt_getprop(fdt, node, "ranges", &len);
+		if (len % range_length != 0) {
+			continue;
+		}
+
+		while (len >= range_length) {
+			uint32_t pci_addr_flags;
+			uintptr_t pci_addr;
+			uintptr_t cpu_addr;
+			uintptr_t size;
+			const uint32_t *cells;
+
+			cells = val;
+			pci_addr_flags = fdt32_to_cpu(cells[0]);
+			pci_addr = fdt64_to_cpu(*(fdt64_t *)(&cells[1]));
+			cpu_addr = fdt64_to_cpu(*(fdt64_t *)(&cells[3]));
+			size = fdt64_to_cpu(*(fdt64_t *)(&cells[5]));
+
+			if (pci_addr_flags == 0x02000000 &&
+			    pci_addr == cpu_addr) {
+				/* Add as I/O memory */
+				qoriq_mmu_add(
+					context,
+					cpu_addr,
+					cpu_addr + size - 1,
+					0,
+					FSL_EIS_MAS2_I | FSL_EIS_MAS2_G,
+					FSL_EIS_MAS3_SR | FSL_EIS_MAS3_SW,
+					0
+				);
+			}
+			len -= range_length;
+			val += range_length;
+		}
+	}
+}
+
 void TEXT qoriq_mmu_config(bool boot_processor, int first_tlb, int scratch_tlb)
 {
 	qoriq_mmu_context context;
@@ -349,6 +435,8 @@ void TEXT qoriq_mmu_config(bool boot_processor, int first_tlb, int scratch_tlb)
 		}
 	}
 
+	add_pcie_regions(&context, fdt);
+
 	qoriq_mmu_partition(&context, max_count);
 	qoriq_mmu_write_to_tlb1(&context, first_tlb);
 }
-- 
2.35.3



More information about the devel mailing list