From 03474861489093515bba718c67a6fade33596dd1 Mon Sep 17 00:00:00 2001 From: Mitchel Humpherys Date: Fri, 8 Aug 2014 16:18:36 -0700 Subject: [PATCH] iommu/arm-smmu: program ACTLR register for qcom SMMUs The ACTLR must be programmed according to the hardware design in order for the coherent table walk feature to work on certain Qualcomm hardware. Provide a new compatible string ("qcom,smmu-v2") to indicate the relevant hardware and do the programming as needed. Change-Id: I7e807384c821fc3d07274f35726abb28d0d75ee0 Signed-off-by: Mitchel Humpherys --- .../devicetree/bindings/iommu/arm,smmu.txt | 1 + drivers/iommu/arm-smmu.c | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 2df61831092f..4a2e4bacd914 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -16,6 +16,7 @@ conditions. "arm,mmu-400" "arm,mmu-401" "arm,mmu-500" + "qcom,smmu-v2" depending on the particular implementation and/or the version of the architecture implemented. diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 0cd8fbbda22a..389befcc58c6 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -229,6 +229,7 @@ #define ARM_SMMU_CB(smmu, n) ((n) * (1 << (smmu)->pgshift)) #define ARM_SMMU_CB_SCTLR 0x0 +#define ARM_SMMU_CB_ACTLR 0x4 #define ARM_SMMU_CB_RESUME 0x8 #define ARM_SMMU_CB_TTBCR2 0x10 #define ARM_SMMU_CB_TTBR0_LO 0x20 @@ -331,6 +332,17 @@ #define FSR_AFF (1 << 2) #define FSR_TF (1 << 1) +/* Definitions for implementation-defined registers */ +#define ACTLR_QCOM_OSH_SHIFT 28 +#define ACTLR_QCOM_OSH 1 + +#define ACTLR_QCOM_ISH_SHIFT 29 +#define ACTLR_QCOM_ISH 1 + +#define ACTLR_QCOM_NSH_SHIFT 30 +#define ACTLR_QCOM_NSH 1 + + #define FSR_IGN (FSR_AFF | FSR_ASF | \ FSR_TLBMCF | FSR_TLBLKF) #define FSR_FAULT (FSR_MULTI | FSR_SS | FSR_UUT | \ @@ -366,9 +378,16 @@ struct arm_smmu_master { struct arm_smmu_master_cfg cfg; }; +enum smmu_model_id { + SMMU_MODEL_DEFAULT, + SMMU_MODEL_QCOM_V2, +}; + struct arm_smmu_device { struct device *dev; + enum smmu_model_id model; + void __iomem *base; unsigned long size; unsigned long pgshift; @@ -1018,6 +1037,13 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); + if (smmu->model == SMMU_MODEL_QCOM_V2) { + reg = ACTLR_QCOM_ISH << ACTLR_QCOM_ISH_SHIFT | + ACTLR_QCOM_OSH << ACTLR_QCOM_OSH_SHIFT | + ACTLR_QCOM_NSH << ACTLR_QCOM_NSH_SHIFT; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_ACTLR); + } + /* MAIR0 (stage-1 only) */ if (stage1) { reg = (MAIR_ATTR_NC << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_NC)) | @@ -2246,6 +2272,7 @@ static const struct of_device_id arm_smmu_of_match[] = { { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 }, { .compatible = "arm,mmu-401", .data = (void *)ARM_SMMU_V1 }, { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 }, + { .compatible = "qcom,smmu-v2", .data = (void *)ARM_SMMU_V2 }, { }, }; MODULE_DEVICE_TABLE(of, arm_smmu_of_match); @@ -2338,6 +2365,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) parse_driver_options(smmu); + if (of_device_is_compatible(dev->of_node, "qcom,smmu-v2")) + smmu->model = SMMU_MODEL_QCOM_V2; + if (smmu->version > ARM_SMMU_V1 && smmu->num_context_banks != smmu->num_context_irqs) { dev_err(dev,