@@ -47,6 +47,8 @@ to non-secure vs secure interrupt line.
secure lines. (Ie. if the iommu contains secure
context banks)
- qcom,ctx-num : The number associated to the context bank
+- qcom,use-aarch64-pagetables : Switch to AArch64 pagetable format on all
+ contexts declared in this IOMMU
** Examples:
@@ -52,6 +52,7 @@ struct qcom_iommu_dev {
void __iomem *local_base;
u32 sec_id;
u8 num_ctxs;
+ bool use_aarch64_pt;
struct qcom_iommu_ctx *ctxs[]; /* indexed by asid-1 */
};
@@ -164,11 +165,17 @@ static void qcom_iommu_tlb_inv_range_nosync(unsigned long iova, size_t size,
reg = leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
for (i = 0; i < fwspec->num_ids; i++) {
+ struct qcom_iommu_dev *qcom_iommu = qcom_domain->iommu;
struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]);
size_t s = size;
- iova = (iova >> 12) << 12;
- iova |= ctx->asid;
+ if (qcom_iommu->use_aarch64_pt) {
+ iova >>= 12;
+ iova |= (unsigned long)ctx->asid << 48;
+ } else {
+ iova &= (1UL << 12) - 1UL;
+ iova |= ctx->asid;
+ }
do {
iommu_writel(ctx, reg, iova);
iova += granule;
@@ -248,6 +255,8 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct io_pgtable_ops *pgtbl_ops;
struct io_pgtable_cfg pgtbl_cfg;
+ enum io_pgtable_fmt pgtbl_fmt;
+ unsigned long ias, oas;
int i, ret = 0;
u32 reg;
@@ -255,10 +264,19 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
if (qcom_domain->iommu)
goto out_unlock;
+ if (qcom_iommu->use_aarch64_pt) {
+ pgtbl_fmt = ARM_64_LPAE_S1;
+ ias = oas = 48;
+ } else {
+ pgtbl_fmt = ARM_32_LPAE_S1;
+ ias = 32;
+ oas = 40;
+ }
+
pgtbl_cfg = (struct io_pgtable_cfg) {
.pgsize_bitmap = qcom_iommu_ops.pgsize_bitmap,
- .ias = 32,
- .oas = 40,
+ .ias = ias,
+ .oas = oas,
.tlb = &qcom_flush_ops,
.iommu_dev = qcom_iommu->dev,
};
@@ -266,7 +284,7 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
qcom_domain->iommu = qcom_iommu;
qcom_domain->fwspec = fwspec;
- pgtbl_ops = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &pgtbl_cfg, qcom_domain);
+ pgtbl_ops = alloc_io_pgtable_ops(pgtbl_fmt, &pgtbl_cfg, qcom_domain);
if (!pgtbl_ops) {
dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n");
ret = -ENOMEM;
@@ -280,6 +298,7 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
for (i = 0; i < fwspec->num_ids; i++) {
struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]);
+ u32 tcr[2];
if (!ctx->secure_init) {
ret = qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, ctx->asid);
@@ -292,11 +311,25 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
qcom_iommu_reset_ctx(ctx);
+
+ tcr[0] = arm_smmu_lpae_tcr(&pgtbl_cfg);
+ tcr[1] = arm_smmu_lpae_tcr2(&pgtbl_cfg);
+
+ if (!qcom_iommu->use_aarch64_pt) {
+ tcr[0] |= ARM_SMMU_TCR_EAE;
+ } else {
+ /* This shall not fail, or spectacular things happen! */
+ if (qcom_scm_iommu_set_pt_format(qcom_iommu->sec_id, ctx->asid, 1)) {
+ dev_warn(qcom_iommu->dev, "Cannot set AArch64 pt format\n");
+ goto out_clear_iommu;
+ }
+
+ tcr[1] |= ARM_SMMU_TCR2_AS;
+ }
+
/* TCR */
- iommu_writel(ctx, ARM_SMMU_CB_TCR2,
- arm_smmu_lpae_tcr2(&pgtbl_cfg));
- iommu_writel(ctx, ARM_SMMU_CB_TCR,
- arm_smmu_lpae_tcr(&pgtbl_cfg) | ARM_SMMU_TCR_EAE);
+ iommu_writel(ctx, ARM_SMMU_CB_TCR2, tcr[1]);
+ iommu_writel(ctx, ARM_SMMU_CB_TCR, tcr[0]);
/* TTBRs */
iommu_writeq(ctx, ARM_SMMU_CB_TTBR0,
@@ -844,6 +877,9 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (of_property_read_bool(dev->of_node, "qcom,use-aarch64-pagetables"))
+ qcom_iommu->use_aarch64_pt = true;
+
if (qcom_iommu_has_secure_context(qcom_iommu)) {
ret = qcom_iommu_sec_ptbl_init(dev);
if (ret) {