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

Commit fe6c032d authored by Praveen Chidambaram's avatar Praveen Chidambaram Committed by Archana Sathyakumar
Browse files

msm: spm: Support RPM handshake control bit in SPM



SAW2 3.0 supports RPM handshake using SAW2_SPM_CTL register for the
sleep command in the SPM sequence. This allows a single power collapse
sequence for both cases when we don't want to notify RPM on apps power
down and when we want to.

This implementation is the same across all IPs in the apps processor
subsystem, but only a few SAW modules are allowed to notify RPM and
handshake with RPM when executing the 0x03 sleep command. Disallow and
check incorrect call on SPM, based on the flag provided in the device
tree.

Based on this flag in DT, set the SLP_CMD_MODE bit in SPM_CTL
register. Fail to set the low power mode if we are trying to send
rpm notification for a mode that does not support rpm notification.

Change-Id: I5527bd8da62673d68867842dbd80000d67965e6a
Signed-off-by: default avatarArchana Sathyakumar <asathyak@codeaurora.org>
parent 2e272c5b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -57,6 +57,9 @@ Optional properties
- qcom,use-qchannel-for-pc: Boolean property to specify if qchannel should be
	ignored when entering power collapse. If this property is set qchannel
	will not be ignored in power collapse.
- qcom,supports-rpm-hs: Indicates that this SPM instance allow handshake with
RPM processor when executing the sleep command in the SPM sequence. Supported
only on SAW2 v3.0 and above.

Example 1:
	qcom,spm@f9089000 {
+1 −1
Original line number Diff line number Diff line
@@ -213,7 +213,7 @@ int set_l2_mode(struct low_power_ops *ops, int mode, bool notify_rpm)
		lpm = MSM_SPM_MODE_DISABLED;
		break;
	}
	rc = msm_spm_config_low_power_mode(ops->spm, lpm, true);
	rc = msm_spm_config_low_power_mode(ops->spm, lpm, notify_rpm);

	if (rc)
		pr_err("%s: Failed to set L2 low power mode %d, ERR %d",
+27 −7
Original line number Diff line number Diff line
@@ -134,22 +134,41 @@ static inline uint32_t msm_spm_drv_get_num_spm_entry(
	return (dev->reg_shadow[MSM_SPM_REG_SAW2_ID] >> 24) & 0xFF;
}

static inline void msm_spm_drv_set_start_addr(
static inline void msm_spm_drv_set_notify_rpm(
		struct msm_spm_driver_data *dev, bool notify_rpm)
{
	if (dev->major != 0x3)
		return;

	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= ~BIT(17);
	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= notify_rpm << 17;
}

static inline void msm_spm_drv_set_start_addr2(
		struct msm_spm_driver_data *dev, uint32_t addr, bool pc_mode)
{
	addr &= 0x7F;
	addr &= 0x1FF;
	addr <<= 4;
	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= ~0x1FF0;
	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;

	if (dev->major != 0x3)
		return;

	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFEFFFF;
	if (pc_mode)
		dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= 0x00010000;
}

static inline void msm_spm_drv_set_start_addr(
		struct msm_spm_driver_data *dev, uint32_t addr, bool pc_mode)
{
	if (dev->major == 0x3)
		return msm_spm_drv_set_start_addr2(dev, addr, pc_mode);

	addr &= 0x7F;
	addr <<= 4;
	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] &= 0xFFFFF80F;
	dev->reg_shadow[MSM_SPM_REG_SAW2_SPM_CTL] |= addr;
}

static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev)
{
	msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW2_ID);
@@ -299,7 +318,7 @@ int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
}

int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
		uint32_t addr, bool pc_mode)
		uint32_t addr, bool pc_mode, bool notify_rpm)
{

	/* SPM is configured to reset start address to zero after end of Program
@@ -308,6 +327,7 @@ int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
		return -EINVAL;

	msm_spm_drv_set_start_addr(dev, addr, pc_mode);
	msm_spm_drv_set_notify_rpm(dev, notify_rpm);

	msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_SPM_CTL);
	wmb();
+21 −18
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@

struct msm_spm_power_modes {
	uint32_t mode;
	bool notify_rpm;
	uint32_t start_addr;
};

@@ -44,6 +43,7 @@ struct msm_spm_device {
	struct cpumask mask;
	void __iomem *q2s_reg;
	bool qchannel_ignore;
	bool allow_rpm_hs;
};

struct msm_spm_vdd_info {
@@ -201,14 +201,17 @@ static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
		ret = msm_spm_drv_set_spm_enable(&dev->reg_data, false);
	} else if (!msm_spm_drv_set_spm_enable(&dev->reg_data, true)) {
		for (i = 0; i < dev->num_modes; i++) {
			if ((dev->modes[i].mode == mode) &&
				(dev->modes[i].notify_rpm == notify_rpm)) {
			if (dev->modes[i].mode != mode)
				continue;

			if (!dev->allow_rpm_hs && notify_rpm)
				notify_rpm = false;

			start_addr = dev->modes[i].start_addr;
			break;
		}
		}
		ret = msm_spm_drv_set_low_power_mode(&dev->reg_data,
					start_addr, pc_mode);
					start_addr, pc_mode, notify_rpm);
	}

	msm_spm_config_q2s(dev, mode);
@@ -249,10 +252,10 @@ static int msm_spm_dev_init(struct msm_spm_device *dev,
			goto spm_failed_init;

		dev->modes[i].mode = data->modes[i].mode;
		dev->modes[i].notify_rpm = data->modes[i].notify_rpm;
	}
	msm_spm_drv_flush_seq_entry(&dev->reg_data);
	dev->initialized = true;

	return 0;

spm_failed_init:
@@ -552,15 +555,14 @@ static int msm_spm_dev_probe(struct platform_device *pdev)
	struct mode_of {
		char *key;
		uint32_t id;
		uint32_t notify_rpm;
	};

	struct mode_of mode_of_data[] = {
		{"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
		{"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_RETENTION, 0},
		{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_MODE_GDHS, 1},
		{"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
		{"qcom,saw2-spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
		{"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING},
		{"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_RETENTION},
		{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_MODE_GDHS},
		{"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE},
		{"qcom,saw2-spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE},
	};

	dev = msm_spm_get_device(pdev);
@@ -650,16 +652,17 @@ static int msm_spm_dev_probe(struct platform_device *pdev)
		if (!modes[mode_count].cmd)
			continue;
		modes[mode_count].mode = mode_of_data[i].id;
		modes[mode_count].notify_rpm = mode_of_data[i].notify_rpm;
		pr_debug("%s(): dev: %s cmd:%s, mode:%d rpm:%d\n", __func__,
				dev->name, key, modes[mode_count].mode,
				modes[mode_count].notify_rpm);
		pr_debug("%s(): dev: %s cmd:%s, mode:%d\n", __func__,
				dev->name, key, modes[mode_count].mode);
		mode_count++;
	}

	spm_data.modes = modes;
	spm_data.num_modes = mode_count;

	key = "qcom,supports-rpm-hs";
	dev->allow_rpm_hs = of_property_read_bool(pdev->dev.of_node, key);

	ret = msm_spm_dev_init(dev, &spm_data);
	if (ret)
		goto fail;
+1 −1
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ int msm_spm_drv_init(struct msm_spm_driver_data *dev,
		struct msm_spm_platform_data *data);
void msm_spm_drv_reinit(struct msm_spm_driver_data *dev);
int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
		uint32_t addr, bool pc_mode);
		uint32_t addr, bool pc_mode, bool notify_rpm);
int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
		unsigned int vlevel);
void dump_regs(struct msm_spm_driver_data *dev, int cpu);