summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-layerscape/icid.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-layerscape/icid.c')
-rw-r--r--arch/arm/mach-layerscape/icid.c385
1 files changed, 311 insertions, 74 deletions
diff --git a/arch/arm/mach-layerscape/icid.c b/arch/arm/mach-layerscape/icid.c
index b574a554ab..ebe3896075 100644
--- a/arch/arm/mach-layerscape/icid.c
+++ b/arch/arm/mach-layerscape/icid.c
@@ -1,10 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <io.h>
#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>
/*
* Stream IDs on Chassis-2 (for example ls1043a, ls1046a, ls1012) devices
@@ -65,6 +69,72 @@ struct icid_id_table {
phys_addr_t reg_addr;
};
+static void of_set_iommu_prop(struct device_node *np, phandle iommu_handle,
+ int stream_id)
+{
+ u32 prop[] = {
+ iommu_handle,
+ stream_id
+ };
+
+ of_property_write_u32_array(np, "iommus", prop, ARRAY_SIZE(prop));
+}
+
+static phandle of_get_iommu_handle(struct device_node *root)
+{
+ struct device_node *iommu;
+
+ iommu = of_find_compatible_node(root, NULL, "arm,mmu-500");
+ if (!iommu) {
+ pr_info("No \"arm,mmu-500\" node found, won't fixup\n");
+ return 0;
+ }
+
+ return of_node_create_phandle(iommu);
+}
+
+static int of_fixup_icid(struct device_node *root, phandle iommu_handle,
+ const struct icid_id_table *icid_table, int num_icid)
+{
+ int i;
+
+ for (i = 0; i < num_icid; i++) {
+ const struct icid_id_table *icid = &icid_table[i];
+ struct device_node *np;
+
+ if (!icid->compat)
+ continue;
+
+ for_each_compatible_node_from(np, root, NULL, icid->compat) {
+ struct resource res;
+
+ if (of_address_to_resource(np, 0, &res))
+ continue;
+
+ if (res.start == icid->compat_addr) {
+ of_set_iommu_prop(np, iommu_handle, icid->id);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void setup_icid_offsets(const struct icid_id_table *icid_table, int num_icids, bool le)
+{
+ int i;
+
+ for (i = 0; i < num_icids; i++) {
+ const struct icid_id_table *icid = &icid_table[i];
+
+ if (le)
+ out_le32((u32 *)(icid->reg_addr), icid->reg);
+ else
+ out_be32((u32 *)(icid->reg_addr), icid->reg);
+ }
+}
+
struct fman_icid_id_table {
u32 port_id;
u32 icid;
@@ -78,7 +148,7 @@ struct fman_icid_id_table {
#define SEC_QIIC_LS 0x70024
#define SEC_IRBAR_JRn(n) (0x10000 * ((n) + 1))
-struct icid_id_table icid_tbl_ls1046a[] = {
+static const struct icid_id_table icid_tbl_ls1046a[] = {
{
.compat = "fsl,qman",
.id = DPAA1_SID_START,
@@ -206,7 +276,7 @@ struct icid_id_table icid_tbl_ls1046a[] = {
},
};
-struct fman_icid_id_table fman_icid_tbl_ls1046a[] = {
+static const struct fman_icid_id_table fman_icid_tbl_ls1046a[] = {
{
.port_id = 0x02,
.icid = DPAA1_SID_END,
@@ -276,7 +346,7 @@ struct fman_icid_id_table fman_icid_tbl_ls1046a[] = {
},
};
-static int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl,
+static int get_fman_port_icid(int port_id, const struct fman_icid_id_table *tbl,
const int size)
{
int i;
@@ -289,24 +359,13 @@ static int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl,
return -ENODEV;
}
-static void fdt_set_iommu_prop(struct device_node *np, phandle iommu_handle,
- int stream_id)
-{
- u32 prop[2];
-
- prop[0] = cpu_to_fdt32(iommu_handle);
- prop[1] = cpu_to_fdt32(stream_id);
-
- of_set_property(np, "iommus", prop, sizeof(prop), 1);
-}
-
-static void fdt_fixup_fman_port_icid_by_compat(struct device_node *root,
+static void of_fixup_fman_port_icid_by_compat(struct device_node *root,
phandle iommu_handle,
const char *compat)
{
struct device_node *np;
- int ret;
- u32 cell_index, icid;
+ int ret, icid;
+ u32 cell_index;
for_each_compatible_node_from(np, root, NULL, compat) {
ret = of_property_read_u32(np, "cell-index", &cell_index);
@@ -321,11 +380,11 @@ static void fdt_fixup_fman_port_icid_by_compat(struct device_node *root,
continue;
}
- fdt_set_iommu_prop(np, iommu_handle, icid);
+ of_set_iommu_prop(np, iommu_handle, icid);
}
}
-static void fdt_fixup_fman_icids(struct device_node *root, phandle iommu_handle)
+static void of_fixup_fman_icids(struct device_node *root, phandle iommu_handle)
{
static const char * const compats[] = {
"fsl,fman-v3-port-oh",
@@ -335,7 +394,7 @@ static void fdt_fixup_fman_icids(struct device_node *root, phandle iommu_handle)
int i;
for (i = 0; i < ARRAY_SIZE(compats); i++)
- fdt_fixup_fman_port_icid_by_compat(root, iommu_handle, compats[i]);
+ of_fixup_fman_port_icid_by_compat(root, iommu_handle, compats[i]);
}
struct qportal_info {
@@ -345,7 +404,7 @@ struct qportal_info {
u8 sdest;
};
-struct qportal_info qp_info[] = {
+static const struct qportal_info qp_info[] = {
{
.dicid = DPAA1_SID_END,
.ficid = DPAA1_SID_END,
@@ -437,7 +496,7 @@ static void setup_qbman_portals(void)
out_be32(&qman->qcsp_bar, (u32)QMAN_MEM_PHYS);
for (i = 0; i < ARRAY_SIZE(qp_info); i++) {
- struct qportal_info *qi = &qp_info[i];
+ const struct qportal_info *qi = &qp_info[i];
out_be32(&qman->qcsp[i].qcsp_lio_cfg, (qi->icid << 16) | qi->dicid);
/* set frame icid */
@@ -449,22 +508,22 @@ static void setup_qbman_portals(void)
inhibit_portals(qpaddr, ARRAY_SIZE(qp_info), QMAN_SP_CINH_SIZE);
}
-static void fdt_set_qportal_iommu_prop(struct device_node *np, phandle iommu_handle,
- struct qportal_info *qp_info)
+static void of_set_qportal_iommu_prop(struct device_node *np, phandle iommu_handle,
+ const struct qportal_info *qp_info)
{
- u32 prop[6];
-
- prop[0] = cpu_to_fdt32(iommu_handle);
- prop[1] = cpu_to_fdt32(qp_info->icid);
- prop[2] = cpu_to_fdt32(iommu_handle);
- prop[3] = cpu_to_fdt32(qp_info->dicid);
- prop[4] = cpu_to_fdt32(iommu_handle);
- prop[5] = cpu_to_fdt32(qp_info->ficid);
+ u32 prop[] = {
+ iommu_handle,
+ qp_info->icid,
+ iommu_handle,
+ qp_info->dicid,
+ iommu_handle,
+ qp_info->ficid
+ };
- of_set_property(np, "iommus", prop, sizeof(prop), 1);
+ of_property_write_u32_array(np, "iommus", prop, ARRAY_SIZE(prop));
}
-static void fdt_fixup_qportals(struct device_node *root, phandle iommu_handle)
+static void of_fixup_qportals(struct device_node *root, phandle iommu_handle)
{
struct device_node *np;
unsigned int maj, min;
@@ -484,75 +543,253 @@ static void fdt_fixup_qportals(struct device_node *root, phandle iommu_handle)
if (ret)
continue;
- fdt_set_qportal_iommu_prop(np, iommu_handle, &qp_info[cell_index]);
+ of_set_qportal_iommu_prop(np, iommu_handle, &qp_info[cell_index]);
}
}
-static int icid_of_fixup(struct device_node *root, void *context)
+static int of_fixup_ls1046a(struct device_node *root, void *context)
{
- int i;
- struct device_node *iommu;
phandle iommu_handle;
- iommu = of_find_compatible_node(root, NULL, "arm,mmu-500");
- if (!iommu)
- return -ENOENT;
+ iommu_handle = of_get_iommu_handle(root);
+ if (!iommu_handle)
+ return 0;
- iommu_handle = of_node_create_phandle(iommu);
+ of_fixup_icid(root, iommu_handle, icid_tbl_ls1046a, ARRAY_SIZE(icid_tbl_ls1046a));
+ of_fixup_fman_icids(root, iommu_handle);
+ of_fixup_qportals(root, iommu_handle);
- for (i = 0; i < ARRAY_SIZE(icid_tbl_ls1046a); i++) {
- struct icid_id_table *icid = &icid_tbl_ls1046a[i];
- struct device_node *np;
+ return 0;
+}
- if (!icid->compat)
- continue;
+void ls1046a_setup_icids(void)
+{
+ struct ccsr_fman *fm = (void *)LSCH2_FM1_ADDR;
+ int i;
- for_each_compatible_node_from(np, root, NULL, icid->compat) {
- struct resource res;
+ setup_icid_offsets(icid_tbl_ls1046a, ARRAY_SIZE(icid_tbl_ls1046a), false);
- if (of_address_to_resource(np, 0, &res))
- continue;
+ /* setup fman icids */
+ for (i = 0; i < ARRAY_SIZE(fman_icid_tbl_ls1046a); i++) {
+ const struct fman_icid_id_table *icid = &fman_icid_tbl_ls1046a[i];
- if (res.start == icid->compat_addr) {
- fdt_set_iommu_prop(np, iommu_handle, icid->id);
- break;
- }
- }
+ out_be32(&fm->fm_bmi_common.fmbm_ppid[icid->port_id - 1],
+ icid->icid);
}
- fdt_fixup_fman_icids(root, iommu_handle);
- fdt_fixup_qportals(root, iommu_handle);
+ setup_qbman_portals();
+
+ 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;
}
-static int layerscape_setup_icids(void)
+/* 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;
- struct ccsr_fman *fm = (void *)LSCH2_FM1_ADDR;
- if (!of_machine_is_compatible("fsl,ls1046a"))
- return 0;
+ out_le32(ECAM_IERB_MSICAR, ECAM_IERB_MSICAR_VALUE);
- /* setup general icid offsets */
- for (i = 0; i < ARRAY_SIZE(icid_tbl_ls1046a); i++) {
- struct icid_id_table *icid = &icid_tbl_ls1046a[i];
+ for (i = 0; i < ARRAY_SIZE(ierb_offset); i++) {
+ if (ierb_offset[i] < 0)
+ continue;
- out_be32((u32 *)(icid->reg_addr), icid->reg);
+ out_le32(ECAM_IERB_BASE + ierb_offset[i],
+ FSL_ECAM_STREAM_ID_START + i);
}
+}
- /* setup fman icids */
- for (i = 0; i < ARRAY_SIZE(fman_icid_tbl_ls1046a); i++) {
- struct fman_icid_id_table *icid = &fman_icid_tbl_ls1046a[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];
- out_be32(&fm->fm_bmi_common.fmbm_ppid[icid->port_id - 1],
- icid->icid);
+ 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;
}
- setup_qbman_portals();
+ 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;
+ }
- of_register_fixup(icid_of_fixup, NULL);
+ 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;
}
-coredevice_initcall(layerscape_setup_icids);
+
+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);
+}