[PATCH v2 11/21] ARM: Layerscape: LS1028a: fixup icids

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The DMA operations from peripherals have a stream id attached to them
which must match the stream ids configured in the IOMMU. Configure the
stream ids in the peripheral registers and fixup the Kernel device tree
with the configured stream ids.
The code is based on the corresponding U-Boot code as of
U-Boot-2023.10-rc1. The result is hard to match against the U-Boot code
though as U-Boot hides the initialisation arrays behind multiply layered
defines which are dropped here to make the code readable.

Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>
---
 arch/arm/mach-layerscape/icid.c      | 213 +++++++++++++++++++++++++++
 arch/arm/mach-layerscape/soc.c       |   1 +
 include/mach/layerscape/layerscape.h |   1 +
 3 files changed, 215 insertions(+)

diff --git a/arch/arm/mach-layerscape/icid.c b/arch/arm/mach-layerscape/icid.c
index 3207d55bf0..ebe3896075 100644
--- a/arch/arm/mach-layerscape/icid.c
+++ b/arch/arm/mach-layerscape/icid.c
@@ -5,6 +5,7 @@
 #include <init.h>
 #include <of_address.h>
 #include <soc/fsl/immap_lsch2.h>
+#include <soc/fsl/immap_lsch3.h>
 #include <soc/fsl/fsl_qbman.h>
 #include <soc/fsl/fsl_fman.h>
 #include <mach/layerscape/layerscape.h>
@@ -580,3 +581,215 @@ void ls1046a_setup_icids(void)
 
 	of_register_fixup(of_fixup_ls1046a, NULL);
 }
+
+static const struct icid_id_table icid_tbl_ls1028a[] = {
+	{
+		.compat = "snps,dwc3",
+		.id = 1,
+		.reg = 1,
+		.compat_addr = LSCH3_XHCI_USB1_ADDR,
+		.reg_addr = offsetof(struct lsch3_ccsr_gur, usb1_amqr) + LSCH3_GUTS_ADDR,
+	}, {
+		.compat = "snps,dwc3",
+		.id = 2,
+		.reg = 2,
+		.compat_addr = LSCH3_XHCI_USB2_ADDR,
+		.reg_addr = offsetof(struct lsch3_ccsr_gur, usb2_amqr) + LSCH3_GUTS_ADDR,
+	}, {
+		.compat = "fsl,esdhc",
+		.id = 3,
+		.reg = 3,
+		.compat_addr = LSCH3_ESDHC1_BASE_ADDR,
+		.reg_addr = offsetof(struct lsch3_ccsr_gur, sdmm1_amqr) + LSCH3_GUTS_ADDR,
+	}, {
+		.compat = "fsl,esdhc",
+		.id = 69,
+		.reg = 69,
+		.compat_addr = LSCH3_ESDHC2_BASE_ADDR,
+		.reg_addr = offsetof(struct lsch3_ccsr_gur, sdmm2_amqr) + LSCH3_GUTS_ADDR,
+	}, {
+		.compat = "fsl,ls1028a-ahci",
+		.id = 4,
+		.reg = 4,
+		.compat_addr = LSCH3_AHCI1_ADDR,
+		.reg_addr = offsetof(struct lsch3_ccsr_gur, sata1_amqr) + LSCH3_GUTS_ADDR,
+	}, {
+		.compat = "fsl,vf610-edma",
+		.id = 40,
+		.reg = 40,
+		.compat_addr = LSCH3_EDMA_ADDR,
+		.reg_addr = offsetof(struct lsch3_ccsr_gur, spare3_amqr) + LSCH3_GUTS_ADDR,
+	},  {
+		.compat = "fsl,ls1028a-qdma",
+		.id = 5,
+		.reg = (1 << 31) | 5,
+		.compat_addr = LSCH3_QDMA_ADDR,
+		.reg_addr = LSCH3_QDMA_ADDR + QMAN_CQSIDR_REG,
+	}, {
+		.compat = NULL,
+		.id = 5,
+		.reg = (1 << 31) | 5,
+		.compat_addr = LSCH3_QDMA_ADDR,
+		.reg_addr = LSCH3_QDMA_ADDR + QMAN_CQSIDR_REG + 4,
+	}, {
+		.compat = "vivante,gc",
+		.id = 71,
+		.reg = 71,
+		.compat_addr = LSCH3_GPU_ADDR,
+		.reg_addr = offsetof(struct lsch3_ccsr_gur, misc1_amqr) + LSCH3_GUTS_ADDR,
+	}, {
+		.compat = "arm,mali-dp500",
+		.id = 72,
+		.reg = 72,
+		.compat_addr = LSCH3_DISPLAY_ADDR,
+		.reg_addr = offsetof(struct lsch3_ccsr_gur, spare2_amqr) + LSCH3_GUTS_ADDR,
+	}, {
+		.compat = "fsl,sec-v4.0-job-ring",
+		.id = 65,
+		.reg = 65,
+		.compat_addr = LSCH3_SEC_JR0_ADDR,
+		.reg_addr = offsetof(struct ccsr_sec, jrliodnr[0].ls) + LSCH3_SEC_ADDR,
+        }, {
+		.compat = "fsl,sec-v4.0-job-ring",
+		.id = 66,
+		.reg = 66,
+		.compat_addr = LSCH3_SEC_JR1_ADDR,
+		.reg_addr = offsetof(struct ccsr_sec, jrliodnr[1].ls) + LSCH3_SEC_ADDR,
+	}, {
+		.id = 67,
+		.reg = 67,
+		.compat_addr = LSCH3_SEC_JR2_ADDR,
+		.reg_addr = offsetof(struct ccsr_sec, jrliodnr[2].ls) + LSCH3_SEC_ADDR,
+	}, {
+		.compat = "fsl,sec-v4.0-job-ring",
+		.id = 68,
+		.reg = 68,
+		.compat_addr = LSCH3_SEC_JR3_ADDR,
+		.reg_addr = offsetof(struct ccsr_sec, jrliodnr[3].ls) + LSCH3_SEC_ADDR,
+	}, {
+		.id = 64,
+		.reg = 64,
+		.compat_addr = 0,
+		.reg_addr = offsetof(struct ccsr_sec, rticliodnr[0].ls) + LSCH3_SEC_ADDR,
+	}, {
+		.id = 64,
+		.reg = 64,
+		.compat_addr = 0,
+		.reg_addr = offsetof(struct ccsr_sec, rticliodnr[1].ls) + LSCH3_SEC_ADDR,
+	}, {
+		.id = 64,
+		.reg = 64,
+		.compat_addr = 0,
+		.reg_addr = offsetof(struct ccsr_sec, rticliodnr[2].ls) + LSCH3_SEC_ADDR,
+	}, {
+		.id = 64,
+		.reg = 64,
+		.compat_addr = 0,
+		.reg_addr = offsetof(struct ccsr_sec, rticliodnr[3].ls) + LSCH3_SEC_ADDR,
+	}, {
+		.id = 64,
+		.reg = 64,
+		.compat_addr = 0,
+		.reg_addr = offsetof(struct ccsr_sec, decoliodnr[0].ls) + LSCH3_SEC_ADDR,
+	}, {
+		.id = 64,
+		.reg = 64,
+		.compat_addr = 0,
+		.reg_addr = offsetof(struct ccsr_sec, decoliodnr[1].ls) + LSCH3_SEC_ADDR,
+	}
+};
+
+static int of_fixup_icid_ls1028a(struct device_node *root, void *context)
+{
+	phandle iommu_handle;
+
+	iommu_handle = of_get_iommu_handle(root);
+	if (!iommu_handle)
+		return 0;
+
+	of_fixup_icid(root, iommu_handle, icid_tbl_ls1028a, ARRAY_SIZE(icid_tbl_ls1028a));
+
+	return 0;
+}
+
+/* offset of IERB config register per PCI function */
+static const int ierb_offset[] = {
+	0x0800,
+	0x1800,
+	0x2800,
+	0x3800,
+	0x4800,
+	0x5800,
+	0x6800,
+	-1,
+	0x0804,
+	0x0808,
+	0x1804,
+	0x1808,
+};
+
+#define ECAM_IERB_BASE                0x1f0800000ULL
+#define ECAM_IERB_MSICAR              (ECAM_IERB_BASE + 0xa400)
+#define ECAM_IERB_MSICAR_VALUE                0x30
+#define FSL_ECAM_STREAM_ID_START 41
+
+/*
+ * Use a custom function for LS1028A, for now this is the only SoC with IERB
+ * and we're currently considering reorganizing IERB for future SoCs.
+ */
+static void ls1028a_set_ecam_icids(void)
+{
+	int i;
+
+	out_le32(ECAM_IERB_MSICAR, ECAM_IERB_MSICAR_VALUE);
+
+	for (i = 0; i < ARRAY_SIZE(ierb_offset); i++) {
+		if (ierb_offset[i] < 0)
+			continue;
+
+		out_le32(ECAM_IERB_BASE + ierb_offset[i],
+			 FSL_ECAM_STREAM_ID_START + i);
+	}
+}
+
+static int of_fixup_ecam_ls1028a(struct device_node *root, void *context)
+{
+	struct device_node *np;
+	int i, ret;
+	const char *props[] = { "msi-map", "iommu-map" };
+	uint32_t map[4];
+
+	np = of_find_compatible_node(root, NULL, "pci-host-ecam-generic");
+	if (!np) {
+		pr_info("No \"pci-host-ecam-generic\" node found, won't fixup\n");
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(props); i++) {
+		ret = of_property_read_u32_array(np, props[i], map, 4);
+		if (ret) {
+			pr_err("Cannot read \"%s\" property: %pe", props[i], ERR_PTR(ret));
+			return ret;
+		}
+
+		map[2] = FSL_ECAM_STREAM_ID_START;
+		map[3] = ARRAY_SIZE(ierb_offset);
+		ret = of_property_write_u32_array(np, props[i], map, 4);
+		if (ret) {
+			pr_err("Cannot write \"%s\" property: %pe", props[i], ERR_PTR(ret));
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+void ls1028a_setup_icids(void)
+{
+	setup_icid_offsets(icid_tbl_ls1028a, ARRAY_SIZE(icid_tbl_ls1028a), true);
+
+	ls1028a_set_ecam_icids();
+
+	of_register_fixup(of_fixup_icid_ls1028a, NULL);
+	of_register_fixup(of_fixup_ecam_ls1028a, NULL);
+}
diff --git a/arch/arm/mach-layerscape/soc.c b/arch/arm/mach-layerscape/soc.c
index 8507a66ff6..a50aafc954 100644
--- a/arch/arm/mach-layerscape/soc.c
+++ b/arch/arm/mach-layerscape/soc.c
@@ -93,6 +93,7 @@ static int ls1028a_init(void)
 		return -EINVAL;
 
 	layerscape_register_pbl_image_handler();
+	ls1028a_setup_icids();
 
 	return 0;
 }
diff --git a/include/mach/layerscape/layerscape.h b/include/mach/layerscape/layerscape.h
index 3dacfcb29f..a9037125c8 100644
--- a/include/mach/layerscape/layerscape.h
+++ b/include/mach/layerscape/layerscape.h
@@ -58,6 +58,7 @@ void ls1046a_bootsource_init(void);
 void layerscape_register_pbl_image_handler(void);
 void ls102xa_smmu_stream_id_init(void);
 void ls1021a_restart_register_feature(void);
+void ls1028a_setup_icids(void);
 void ls1046a_setup_icids(void);
 
 extern int __layerscape_soc_type;
-- 
2.39.2





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux