diff options
-rw-r--r-- | drivers/bus/fsl-mc/fsl-mc-bus.c | 90 |
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 |