@@ -39,6 +39,8 @@ to non-secure vs secure interrupt line.
- reg : Base address and size of context bank within the iommu
- interrupts : The context fault irq.
- 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
** Optional properties:
@@ -48,6 +48,7 @@ struct qcom_iommu_dev {
void __iomem *local_base;
u32 sec_id;
u8 num_ctxs;
+ bool use_aarch64_pt;
struct qcom_iommu_ctx *ctxs[0]; /* indexed by asid-1 */
};
@@ -153,11 +154,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 = to_iommu(fwspec);
struct qcom_iommu_ctx *ctx = to_ctx(fwspec, fwspec->ids[i]);
size_t s = size;
- iova &= ~12UL;
- iova |= ctx->asid;
+ if (qcom_iommu->use_aarch64_pt) {
+ iova >>= 12;
+ iova |= (u64)ctx->asid << 48;
+ } else {
+ iova &= ~12UL;
+ iova |= ctx->asid;
+ }
do {
iommu_writel(ctx, reg, iova);
iova += granule;
@@ -222,6 +229,8 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
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;
@@ -229,16 +238,25 @@ 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_gather_ops,
.iommu_dev = qcom_iommu->dev,
};
qcom_domain->iommu = qcom_iommu;
- pgtbl_ops = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &pgtbl_cfg, fwspec);
+ pgtbl_ops = alloc_io_pgtable_ops(pgtbl_fmt, &pgtbl_cfg, fwspec);
if (!pgtbl_ops) {
dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n");
ret = -ENOMEM;
@@ -252,6 +270,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(fwspec, fwspec->ids[i]);
+ u32 tcr[2];
if (!ctx->secure_init) {
ret = qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, ctx->asid);
@@ -264,12 +283,25 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
qcom_iommu_reset_ctx(ctx);
+ tcr[0] = pgtbl_cfg.arm_lpae_s1_cfg.tcr;
+ tcr[1] = pgtbl_cfg.arm_lpae_s1_cfg.tcr >> 32;
+ tcr[1] |= FIELD_PREP(TCR2_SEP, TCR2_SEP_UPSTREAM);
+
+ if (qcom_iommu->use_aarch64_pt) {
+ /* 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] |= TCR2_AS;
+ }
+
/* TCR */
- iommu_writel(ctx, ARM_SMMU_CB_TCR2,
- (pgtbl_cfg.arm_lpae_s1_cfg.tcr >> 32) |
- FIELD_PREP(TCR2_SEP, TCR2_SEP_UPSTREAM));
- iommu_writel(ctx, ARM_SMMU_CB_TCR,
- pgtbl_cfg.arm_lpae_s1_cfg.tcr);
+ 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 +876,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) {