From: Magnus Damm <damm+renesas@xxxxxxxxxxxxx> Here's a prototype that enables IMCTR_VA64 support for the IPMMU driver on R-Car Gen3 platforms. I've tested it lightly on r8a7796 Salvator-X with local second serial port code and SYS-DMAC support via DMA Engine. My goal has been to enable 40 bits or more of IOVA space, but it turns out that it requires either 64K page size support or support for 4K pages starting from level 0. For now this keeps 32-bit IOVA space however the hardware gets configured to enable IMCTR_VA64 which also seems to require setting up TSZ0[5:0]. Signed-off-by: Magnus Damm <damm+renesas@xxxxxxxxxxxxx> --- Developed on top of renesas-drivers-2017-01-10-v4.10-rc3 drivers/iommu/ipmmu-vmsa.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) --- 0001/drivers/iommu/ipmmu-vmsa.c +++ work/drivers/iommu/ipmmu-vmsa.c 2017-01-23 20:43:31.200607110 +0900 @@ -39,6 +39,7 @@ struct ipmmu_features { bool has_eight_ctx; bool setup_imbuscr; bool twobit_imttbcr_sl0; + bool imctr_va64; }; struct ipmmu_vmsa_device { @@ -117,6 +118,7 @@ static void set_archdata(struct device * #define IM_CTX_SIZE 0x40 #define IMCTR 0x0000 +#define IMCTR_VA64 (1 << 29) #define IMCTR_TRE (1 << 17) #define IMCTR_AFE (1 << 16) #define IMCTR_RTSEL_MASK (3 << 4) @@ -430,8 +432,9 @@ static int ipmmu_domain_init_context(str */ domain->cfg.iommu_dev = domain->root->dev; - domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg, - domain); + domain->iop = alloc_io_pgtable_ops(domain->root->features->imctr_va64 ? + ARM_64_LPAE_S1 : ARM_32_LPAE_S1, + &domain->cfg, domain); if (!domain->iop) return -EINVAL; @@ -462,6 +465,12 @@ static int ipmmu_domain_init_context(str else tmp = IMTTBCR_SL0_LVL_1; + /* + * For IMCTR_VA64 and ARM_64_LPAE_S1 we need lowest bits of TTBCR + */ + if (domain->root->features->imctr_va64) + tmp |= 32; + ipmmu_ctx_write(domain, IMTTBCR, IMTTBCR_EAE | IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | IMTTBCR_IRGN0_WB_WA | tmp); @@ -488,7 +497,8 @@ static int ipmmu_domain_init_context(str * required when modifying the context registers. */ ipmmu_ctx_write2(domain, IMCTR, - IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); + (domain->root->features->imctr_va64 ? IMCTR_VA64 : 0) + | IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); return 0; } @@ -1098,6 +1108,7 @@ static const struct ipmmu_features ipmmu .has_eight_ctx = false, .setup_imbuscr = true, .twobit_imttbcr_sl0 = false, + .imctr_va64 = false, }; static const struct ipmmu_features ipmmu_features_rcar_gen3 = { @@ -1106,6 +1117,7 @@ static const struct ipmmu_features ipmmu .has_eight_ctx = true, .setup_imbuscr = false, .twobit_imttbcr_sl0 = true, + .imctr_va64 = true, }; static const struct of_device_id ipmmu_of_ids[] = {