Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65abde80 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "iommu/arm-smmu: add option to enable halt/resume of SMMU"

parents 42550f97 f8464885
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@
#include <trace/events/iommu.h>
#include <soc/qcom/msm_tz_smmu.h>
#include <soc/qcom/scm.h>
#include <linux/notifier.h>

#include <linux/amba/bus.h>

@@ -440,6 +441,7 @@ struct arm_smmu_device {
#define ARM_SMMU_OPT_DISABLE_ATOS	(1 << 6)
#define ARM_SMMU_OPT_MMU500_ERRATA1	(1 << 7)
#define ARM_SMMU_OPT_STATIC_CB		(1 << 8)
#define ARM_SMMU_OPT_HALT		(1 << 9)
	u32				options;
	enum arm_smmu_arch_version	version;
	enum arm_smmu_implementation	model;
@@ -473,6 +475,7 @@ struct arm_smmu_device {
	unsigned int			num_impl_def_attach_registers;

	struct arm_smmu_power_resources *pwr;
	struct notifier_block		regulator_nb;

	spinlock_t			atos_lock;

@@ -570,6 +573,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
	{ ARM_SMMU_OPT_DISABLE_ATOS, "qcom,disable-atos" },
	{ ARM_SMMU_OPT_MMU500_ERRATA1, "qcom,mmu500-errata-1" },
	{ ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"},
	{ ARM_SMMU_OPT_HALT, "qcom,enable-smmu-halt"},
	{ 0, NULL},
};

@@ -3817,6 +3821,71 @@ static int arm_smmu_init_clocks(struct arm_smmu_power_resources *pwr)
	return 0;
}

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);

	if (event != REGULATOR_EVENT_PRE_DISABLE &&
	    event != REGULATOR_EVENT_ENABLE)
		return NOTIFY_OK;

	ret = arm_smmu_prepare_clocks(smmu->pwr);
	if (ret)
		goto out;

	ret = arm_smmu_power_on_atomic(smmu->pwr);
	if (ret)
		goto unprepare_clock;

	if (event == REGULATOR_EVENT_PRE_DISABLE)
		qsmmuv2_halt(smmu);
	else if (event == REGULATOR_EVENT_ENABLE) {
		if (arm_smmu_restore_sec_cfg(smmu))
			goto power_off;
		qsmmuv2_resume(smmu);
	}
power_off:
	arm_smmu_power_off_atomic(smmu->pwr);
unprepare_clock:
	arm_smmu_unprepare_clocks(smmu->pwr);
out:
	return NOTIFY_OK;
}

static int register_regulator_notifier(struct arm_smmu_device *smmu)
{
	struct device *dev = smmu->dev;
	struct regulator_bulk_data *consumers;
	int ret = 0, num_consumers;
	struct arm_smmu_power_resources *pwr = smmu->pwr;

	if (!(smmu->options & ARM_SMMU_OPT_HALT))
		goto out;

	num_consumers = pwr->num_gdscs;
	consumers = pwr->gdscs;

	if (!num_consumers) {
		dev_info(dev, "no regulator info exist for %s\n",
			 dev_name(dev));
		goto out;
	}

	smmu->regulator_nb.notifier_call = regulator_notifier;
	/* registering the notifier against one gdsc is sufficient as
	 * we do enable/disable regulators in group.
	 */
	ret = regulator_register_notifier(consumers[0].consumer,
					  &smmu->regulator_nb);
	if (ret)
		dev_err(dev, "Regulator notifier request failed\n");
out:
	return ret;
}

static int arm_smmu_init_regulators(struct arm_smmu_power_resources *pwr)
{
	const char *cname;
@@ -4377,6 +4446,11 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
	else
		bus_for_each_dev(&platform_bus_type, NULL, &arm_smmu_ops,
				 arm_smmu_add_device_fixup);

	err = register_regulator_notifier(smmu);
	if (err)
		goto out_power_off;

#ifdef CONFIG_ARM_AMBA
	if (!iommu_present(&amba_bustype))
		bus_set_iommu(&amba_bustype, &arm_smmu_ops);