diff options
| author | Mitchel Humpherys <mitchelh@codeaurora.org> | 2014-08-14 17:44:49 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:11:11 -0700 |
| commit | dbb94a856816edc4b911aea42e5169e0b992d2a2 (patch) | |
| tree | e129e86898935f7e985410a9ae5a166df57bafdc | |
| parent | 1ac0dcf474288ef34f260e2372fd4dbc8a25827f (diff) | |
iommu/arm-smmu: program implementation defined registers on attach
Some platforms require certain implementation-defined registers to be
programmed when first attaching to the SMMU. Add support for this via
specifying register offset, value pairs in the device tree.
Change-Id: Iac2fe42684c3849a24d0d1251a206954262257c5
Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
| -rw-r--r-- | Documentation/devicetree/bindings/iommu/arm,smmu.txt | 8 | ||||
| -rw-r--r-- | drivers/iommu/arm-smmu.c | 69 |
2 files changed, 77 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 4a2e4bacd914..9e6b4a6bf72e 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -74,6 +74,10 @@ conditions. - vdd-supply : Phandle of the regulator that should be powered on during SMMU register access. +- attach-impl-defs : global registers to program at device attach + time. This should be a list of 2-tuples of the format: + <offset reg_value>. + Example: smmu { @@ -93,4 +97,8 @@ Example: */ mmu-masters = <&dma0 0xd01d 0xd01e>, <&dma1 0xd11c>; + + attach-impl-defs = <0x124 0x3>, + <0x128 0xa5>, + <0x12c 0x1>; }; diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 04ef1920cf7c..212deec25113 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -383,6 +383,11 @@ enum smmu_model_id { SMMU_MODEL_QCOM_V2, }; +struct arm_smmu_impl_def_reg { + u32 offset; + u32 value; +}; + struct arm_smmu_device { struct device *dev; @@ -432,6 +437,9 @@ struct arm_smmu_device { struct mutex attach_lock; unsigned int attach_count; + + struct arm_smmu_impl_def_reg *impl_def_attach_registers; + unsigned int num_impl_def_attach_registers; }; struct arm_smmu_cfg { @@ -1378,6 +1386,16 @@ static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain, arm_smmu_disable_clocks(smmu); } +static void arm_smmu_impl_def_programming(struct arm_smmu_device *smmu) +{ + int i; + struct arm_smmu_impl_def_reg *regs = smmu->impl_def_attach_registers; + + for (i = 0; i < smmu->num_impl_def_attach_registers; ++i) + writel_relaxed(regs[i].value, + ARM_SMMU_GR0(smmu) + regs[i].offset); +} + static void arm_smmu_device_reset(struct arm_smmu_device *smmu); static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) @@ -1403,6 +1421,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) arm_smmu_enable_regulators(smmu); arm_smmu_enable_clocks(smmu); arm_smmu_device_reset(smmu); + arm_smmu_impl_def_programming(smmu); } else { arm_smmu_enable_clocks(smmu); } @@ -2109,6 +2128,52 @@ static int arm_smmu_init_clocks(struct arm_smmu_device *smmu) return 0; } +static int arm_smmu_parse_impl_def_registers(struct arm_smmu_device *smmu) +{ + struct device *dev = smmu->dev; + int i, ntuples, ret; + u32 *tuples; + struct arm_smmu_impl_def_reg *regs, *regit; + + if (!of_find_property(dev->of_node, "attach-impl-defs", &ntuples)) + return 0; + + ntuples /= sizeof(u32); + if (ntuples % 2) { + dev_err(dev, + "Invalid number of attach-impl-defs registers: %d\n", + ntuples); + return -EINVAL; + } + + regs = devm_kmalloc( + dev, sizeof(*smmu->impl_def_attach_registers) * ntuples, + GFP_KERNEL); + if (!regs) + return -ENOMEM; + + tuples = devm_kmalloc(dev, sizeof(u32) * ntuples * 2, GFP_KERNEL); + if (!tuples) + return -ENOMEM; + + ret = of_property_read_u32_array(dev->of_node, "attach-impl-defs", + tuples, ntuples); + if (ret) + return ret; + + for (i = 0, regit = regs; i < ntuples; i += 2, ++regit) { + regit->offset = tuples[i]; + regit->value = tuples[i + 1]; + } + + devm_kfree(dev, tuples); + + smmu->impl_def_attach_registers = regs; + smmu->num_impl_def_attach_registers = ntuples / 2; + + return 0; +} + static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) { unsigned long size; @@ -2349,6 +2414,10 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) dev_notice(dev, "registered %d master devices\n", num_masters); + err = arm_smmu_parse_impl_def_registers(smmu); + if (err) + goto out_put_masters; + err = arm_smmu_init_regulators(smmu); if (err) goto out_put_masters; |
