Loading Documentation/devicetree/bindings/iommu/arm,smmu.txt +8 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,14 @@ conditions. useful if the upstream hardware is capable of switching between multiple domains within a single context bank. - qcom,enable-smmu-halt : Before SMMU is powered down, SMMU needs to be in idle state prior to power collapse. When 'halt' is received by SMMU, it ensures that no new requests enters and all outstanding requests are completed and generates an acknowledgment for halt request. So add an option to register a call back notifier on regulators in whcih SMMU can be halted or resumed when regulator is powered down/up. - clocks : List of clocks to be used during SMMU register access. See Documentation/devicetree/bindings/clock/clock-bindings.txt for information about the format. For each clock specified Loading drivers/iommu/arm-smmu.c +51 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/notifier.h> #include <linux/amba/bus.h> #include <soc/qcom/msm_tz_smmu.h> Loading Loading @@ -359,6 +360,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_NO_M (1 << 8) #define ARM_SMMU_OPT_NO_SMR_CHECK (1 << 9) #define ARM_SMMU_OPT_DYNAMIC (1 << 10) #define ARM_SMMU_OPT_HALT (1 << 11) u32 options; enum arm_smmu_arch_version version; Loading @@ -385,6 +387,7 @@ struct arm_smmu_device { struct clk **clocks; struct regulator *gdsc; struct notifier_block regulator_nb; /* Protects against domains attaching to the same SMMU concurrently */ struct mutex attach_lock; Loading Loading @@ -474,6 +477,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_NO_M, "qcom,no-mmu-enable" }, { ARM_SMMU_OPT_NO_SMR_CHECK, "qcom,no-smr-check" }, { ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" }, { ARM_SMMU_OPT_HALT, "qcom,enable-smmu-halt"}, { 0, NULL}, }; Loading Loading @@ -2921,6 +2925,49 @@ static int arm_smmu_id_size_to_bits(int size) } } static int regulator_notifier(struct notifier_block *nb, unsigned long event, void *data) { int ret = 0; struct arm_smmu_device *smmu = container_of(nb, struct arm_smmu_device, regulator_nb); ret = arm_smmu_prepare_clocks(smmu); if (ret) goto out; ret = arm_smmu_enable_clocks_atomic(smmu); if (ret) goto unprepare_clock; if (event == REGULATOR_EVENT_DISABLE) arm_smmu_halt(smmu); else if (event == REGULATOR_EVENT_ENABLE) arm_smmu_resume(smmu); arm_smmu_disable_clocks_atomic(smmu); unprepare_clock: arm_smmu_unprepare_clocks(smmu); out: return ret; } static int register_regulator_notifier(struct arm_smmu_device *smmu) { struct device *dev = smmu->dev; int ret = 0; if (smmu->options & ARM_SMMU_OPT_HALT) { smmu->regulator_nb.notifier_call = regulator_notifier; ret = regulator_register_notifier(smmu->gdsc, &smmu->regulator_nb); if (ret) dev_err(dev, "Regulator notifier request failed\n"); } return ret; } static int arm_smmu_init_regulators(struct arm_smmu_device *smmu) { struct device *dev = smmu->dev; Loading Loading @@ -3349,6 +3396,10 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) idr_init(&smmu->asid_idr); err = register_regulator_notifier(smmu); if (err) goto out_free_irqs; INIT_LIST_HEAD(&smmu->list); spin_lock(&arm_smmu_devices_lock); list_add(&smmu->list, &arm_smmu_devices); Loading Loading
Documentation/devicetree/bindings/iommu/arm,smmu.txt +8 −0 Original line number Diff line number Diff line Loading @@ -110,6 +110,14 @@ conditions. useful if the upstream hardware is capable of switching between multiple domains within a single context bank. - qcom,enable-smmu-halt : Before SMMU is powered down, SMMU needs to be in idle state prior to power collapse. When 'halt' is received by SMMU, it ensures that no new requests enters and all outstanding requests are completed and generates an acknowledgment for halt request. So add an option to register a call back notifier on regulators in whcih SMMU can be halted or resumed when regulator is powered down/up. - clocks : List of clocks to be used during SMMU register access. See Documentation/devicetree/bindings/clock/clock-bindings.txt for information about the format. For each clock specified Loading
drivers/iommu/arm-smmu.c +51 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/notifier.h> #include <linux/amba/bus.h> #include <soc/qcom/msm_tz_smmu.h> Loading Loading @@ -359,6 +360,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_NO_M (1 << 8) #define ARM_SMMU_OPT_NO_SMR_CHECK (1 << 9) #define ARM_SMMU_OPT_DYNAMIC (1 << 10) #define ARM_SMMU_OPT_HALT (1 << 11) u32 options; enum arm_smmu_arch_version version; Loading @@ -385,6 +387,7 @@ struct arm_smmu_device { struct clk **clocks; struct regulator *gdsc; struct notifier_block regulator_nb; /* Protects against domains attaching to the same SMMU concurrently */ struct mutex attach_lock; Loading Loading @@ -474,6 +477,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_NO_M, "qcom,no-mmu-enable" }, { ARM_SMMU_OPT_NO_SMR_CHECK, "qcom,no-smr-check" }, { ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" }, { ARM_SMMU_OPT_HALT, "qcom,enable-smmu-halt"}, { 0, NULL}, }; Loading Loading @@ -2921,6 +2925,49 @@ static int arm_smmu_id_size_to_bits(int size) } } static int regulator_notifier(struct notifier_block *nb, unsigned long event, void *data) { int ret = 0; struct arm_smmu_device *smmu = container_of(nb, struct arm_smmu_device, regulator_nb); ret = arm_smmu_prepare_clocks(smmu); if (ret) goto out; ret = arm_smmu_enable_clocks_atomic(smmu); if (ret) goto unprepare_clock; if (event == REGULATOR_EVENT_DISABLE) arm_smmu_halt(smmu); else if (event == REGULATOR_EVENT_ENABLE) arm_smmu_resume(smmu); arm_smmu_disable_clocks_atomic(smmu); unprepare_clock: arm_smmu_unprepare_clocks(smmu); out: return ret; } static int register_regulator_notifier(struct arm_smmu_device *smmu) { struct device *dev = smmu->dev; int ret = 0; if (smmu->options & ARM_SMMU_OPT_HALT) { smmu->regulator_nb.notifier_call = regulator_notifier; ret = regulator_register_notifier(smmu->gdsc, &smmu->regulator_nb); if (ret) dev_err(dev, "Regulator notifier request failed\n"); } return ret; } static int arm_smmu_init_regulators(struct arm_smmu_device *smmu) { struct device *dev = smmu->dev; Loading Loading @@ -3349,6 +3396,10 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) idr_init(&smmu->asid_idr); err = register_regulator_notifier(smmu); if (err) goto out_free_irqs; INIT_LIST_HEAD(&smmu->list); spin_lock(&arm_smmu_devices_lock); list_add(&smmu->list, &arm_smmu_devices); Loading