summaryrefslogtreecommitdiff
path: root/drivers/bus/fsl-mc/fsl-mc-bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c')
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 8fd4a356a86e..b968b85f5ff3 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -65,6 +65,12 @@ struct fsl_mc_addr_translation_range {
#define GCR1_P1_STOP BIT(31)
#define GCR1_P2_STOP BIT(30)
+#define FSL_MC_FBALR 0x20
+#define MCFBAR_LOW 0xe0000000
+#define MCFBAR_MEMSZ 0x000000ff
+#define FSL_MC_FBAHR 0x24
+#define MCFBAR_HIGH 0x0000ffff
+
#define FSL_MC_FAPR 0x28
#define MC_FAPR_PL BIT(18)
#define MC_FAPR_BMT BIT(17)
@@ -1100,6 +1106,87 @@ static int get_mc_addr_translation_ranges(struct device *dev,
return 0;
}
+static void fsl_mc_setup_iommu(struct device *dev, struct fsl_mc *mc)
+{
+ struct iommu_domain *domain = iommu_get_dma_domain(dev);
+ struct resource dcfg_res = DEFINE_RES_MEM(0x01e00000, 0x10000);
+ struct device_node *np;
+ u64 firmware_base;
+ u64 mc_ram_base;
+ u32 mc_ram_size;
+ u32 mcfbalr;
+ u32 mcfbahr;
+ int ret;
+
+ if (!domain) {
+ dev_err(dev, "Missing IOMMU domain - MC firmware will crash\n");
+ return;
+ }
+
+ mcfbalr = readl(mc->fsl_mc_regs + FSL_MC_FBALR);
+ mcfbahr = readl(mc->fsl_mc_regs + FSL_MC_FBAHR);
+
+ firmware_base = mcfbalr & MCFBAR_LOW;
+ firmware_base |= (u64)(mcfbahr & MCFBAR_HIGH) << 32;
+
+ /* Calculate the size of MC RAM. */
+ mc_ram_size = mcfbalr & MCFBAR_MEMSZ;
+ if (mc_ram_size != 255)
+ mc_ram_size = (mc_ram_size + 1) * SZ_256M;
+ else
+ mc_ram_size = SZ_128M;
+
+ /*
+ * Calculate base address of MC RAM. U-Boot says:
+ * "As per MC design document, MC initial base address should be least
+ * significant 512MB address of MC private memory, i.e. address should
+ * point to end address masked with 512MB offset in private DRAM block."
+ * and uses the following calculation:
+ *
+ * (gd->arch.resv_ram + mc_ram_size - 1) &
+ * MC_RAM_BASE_ADDR_ALIGNMENT_MASK
+ *
+ * where gd->arch.resv_ram is the start of the MC reserved RAM block,
+ * and is itself aligned to 512MB.
+ *
+ * Hence, if the reserved RAM starts at 0x2780000000 and is 0x70000000
+ * in size, then the firmware address will be 0x27e0000000. However,
+ * if it is 512M, then the reserved RAM and the firmware base addresses
+ * will be identical.
+ */
+ mc_ram_base = ALIGN(firmware_base - mc_ram_size + 1, SZ_512M);
+
+ /*
+ * Give MC firmware access to the MC RAM, which includes the MC
+ * firmware image itself.
+ */
+ ret = iommu_map(domain, mc_ram_base, mc_ram_base, mc_ram_size,
+ IOMMU_CACHE | IOMMU_WRITE | IOMMU_READ);
+ if (ret)
+ dev_err(dev, "Failed to setup IOMMU mapping for MC RAM: %pe\n",
+ ERR_PTR(ret));
+
+ /* Give firmware access to the DCFG so it can read the SVR register */
+ np = of_find_compatible_node(NULL, NULL, "fsl,lx2160a-dcfg");
+ if (np) {
+ ret = of_address_to_resource(np, 0, &dcfg_res);
+ if (ret) {
+ dev_err(dev, "Failed to get dcfg resource: %pe\n",
+ ERR_PTR(ret));
+ return;
+ }
+ } else {
+ dev_warn(dev,
+ "Failed to find dcfg node - using default addresses\n");
+ }
+
+ ret = iommu_map(domain, dcfg_res.start, dcfg_res.start,
+ resource_size(&dcfg_res), IOMMU_READ);
+ if (ret)
+ dev_err(dev, "Failed to setup IOMMU mapping for DCFG: %pe\n",
+ ERR_PTR(ret));
+}
+
/*
* fsl_mc_bus_probe - callback invoked when the root MC bus is being
* added
@@ -1151,6 +1238,9 @@ static int fsl_mc_bus_probe(struct platform_device *pdev)
error);
}
+ if (dev_of_node(&pdev->dev))
+ fsl_mc_setup_iommu(&pdev->dev, mc);
+
/*
* Some bootloaders pause the MC firmware before booting the
* kernel so that MC will not cause faults as soon as the