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

Commit 7c220e14 authored by Archana Sathyakumar's avatar Archana Sathyakumar Committed by Matt Wagantall
Browse files

soc: qcom: spm: Split SPM/AVS functionality



SPM DT node supplies all the register information and expects
initialization value for all of them. With PSCI, most of the SPM
programming will be done in EL1 secure and only vctl programming will be
done from HLOS. Change the spm driver to allow write to only those
registers which has initialization values provided in DT.

Change-Id: I073c1c0487bfa98400e234e32f1cc27f20f3b79e
Signed-off-by: default avatarArchana Sathyakumar <asathyak@codeaurora.org>
Signed-off-by: default avatarMurali Nalajala <mnalajal@codeaurora.org>
parent 0036e430
Loading
Loading
Loading
Loading
+44 −44
Original line number Diff line number Diff line
@@ -16,15 +16,20 @@ Required properties
is required on only for SPMs that control the CPU. This field is not required
for SPMs that control L2/CCI/L3
- qcom,saw2-ver-reg: The location of the version register
- qcom,name: The name with which a SPM device is identified by the power
management code.

----------------------------------------------------
Non-PSCI targets should follow the rules shown below
----------------------------------------------------
Required properties for only Non-PSCI targets:

- qcom,saw2-cfg: SAW2 configuration register
- qcom,saw2-spm-ctl: The SPM control register
- qcom,saw2-spm-dly: Provides the values for the SPM delay command in the SPM
	sequence
- qcom,name: The name with which a SPM device is identified by the power
management code.

Optional properties

Optional properties for only Non-PSCI targets
- reg-names: Register names for the physical address required if spm device
        has more than one physical addressed to be mapped. Allowed register
        names are: "saw-base", "q2s", "hw-flush", "slpreq"
@@ -63,7 +68,7 @@ only on SAW2 v3.0 and above.

Second level properties for modes

Required properties
Required properties (if modes node is available)
- qcom,label: Specifies the mode name such as:
            qcom,saw2-spm-cmd-wfi: WFI mode
            qcom,saw2-spm-cmd-ret: Retention mode
@@ -85,15 +90,34 @@ Optional properties
- qcom,event_sync: Specifies event_sync byte should be set in SPM control
	register.

----------------------------------------------------
PSCI targets should follow the rules shown below
----------------------------------------------------
Optional properties for only PSCI targets:

- qcom,saw2-avs-ctl: The AVS control register
- qcom,saw2-avs-hysterisis: The AVS hysterisis register to delay the AVS
	controller requests
- qcom,vctl-timeout-us: The timeout value in us to wait for voltage to change
	after sending the voltage command to the PMIC
- qcom,saw2-avs-limit: The AVS limit register
- qcom,saw2-avs-dly: The AVS delay register is used to specify the delay values
	between AVS controller requests
- qcom,vctl-port: The PVC (PMIC Virtual Channel) port used for changing
	voltage
- qcom,phase-port: The PVC port used for changing the number of phases
- qcom,pfm-port: The PVC port used for enabling PWM/PFM modes
- qcom,cpu-vctl-list: List of cpu node phandles, whose voltage the spm device
	can control.


Example 1:
	qcom,spm@f9089000 {
		compatible = "qcom,spm-v2";
		#address-cells = <1>;
		#size-cells = <1>;
		reg = <0xf9089000 0x1000>,
			<0x9980000 0x4>;
		reg-names = "saw-base", "hw-flush";
		qcom,core-id = <0>;
		reg = <0xf9089000 0x1000>;
		qcom,cpu = <&CPU0>;
		qcom,saw2-ver-reg = <0xfd0>;
		qcom,saw2-cfg = <0x1b>;
		qcom,saw2-avs-ctl = <0>;
@@ -102,7 +126,7 @@ Example 1:
		qcom,saw2-avs-dly= <0>;
		qcom,saw2-spm-dly= <0x20000400>;
		qcom,saw2-spm-ctl = <0x1>;
		qcom,cpu-vctl-mask = <0xf>;
		qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
		qcom,mode0 {
			qcom,label = "qcom,saw2-spm-cmd-wfi";
			qcom,sequence = [03 0b 0f];
@@ -124,46 +148,22 @@ Example 1:
				a0 b0 82 10 30 02 22 30 0f];
			qcom,spm_en;
			qcom,pc_mode;
			qcom,slp_cmd_mode;
		};
	};

Example 2:
	qcom,spm@f9089000 {
	qcom,spm@9A10000 {
		compatible = "qcom,spm-v2";
		#address-cells = <1>;
		#size-cells = <1>;
		reg = <0xf9089000 0x1000>;
		qcom,cpu = <&CPU0>;
		qcom,saw2-ver-reg = <0xfd0>;
		qcom,saw2-cfg = <0x1b>;
		qcom,saw2-avs-ctl = <0>;
		qcom,saw2-avs-hysteresis = <0>;
		qcom,saw2-avs-limit = <0>;
		qcom,saw2-avs-dly= <0>;
		qcom,saw2-spm-dly= <0x20000400>;
		qcom,saw2-spm-ctl = <0x1>;
		reg = <0x9A10000 0x1000>;
		qcom,name = "system-cbf"; /* CBF SAW */
		qcom,saw2-ver-reg = <0xFD0>;
		qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>;
		qcom,mode0 {
			qcom,label = "qcom,saw2-spm-cmd-wfi";
			qcom,sequence = [03 0b 0f];
			qcom,spm_en;
		};

		qcom,mode1 {
			qcom,label = "qcom,saw2-spm-cmd-spc";
			qcom,sequence = [00 20 50 80 60 70 10 92
				a0 b0 03 68 70 3b 92 a0 b0
				82 2b 50 10 30 02 22 30 0f];
			qcom,spm_en;
			qcom,pc_mode;
		qcom,vctl-timeout-us = <50>;
		qcom,vctl-port = <0x0>;
		qcom,phase-port = <0x1>;
		qcom,saw2-avs-ctl = <0x1100>;
		qcom,pfm-port = <0x2>;
};
		qcom,mode2 {
			qcom,label = "qcom,saw2-spm-cmd-pc";
			qcom,sequence = [00 20 10 92 a0 b0 07 3b 92
				a0 b0 82 10 30 02 22 30 0f];
			qcom,spm_en;
			qcom,pc_mode;
		};
	};
+37 −20
Original line number Diff line number Diff line
@@ -120,6 +120,10 @@ static uint32_t num_pmic_data;
static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
		unsigned int reg_index)
{
	BUG_ON(!dev);

	BUG_ON(!dev->reg_shadow);

	__raw_writel(dev->reg_shadow[reg_index],
		dev->reg_base_addr + dev->reg_offsets[reg_index]);
}
@@ -590,17 +594,13 @@ int msm_spm_drv_set_pmic_data(struct msm_spm_driver_data *dev,
	return 0;
}

void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
void msm_spm_drv_reinit(struct msm_spm_driver_data *dev, bool seq_write)
{
	int i;

	if (seq_write)
		msm_spm_drv_flush_seq_entry(dev);

	for (i = 0; i < MSM_SPM_REG_SAW_PMIC_DATA_0 + num_pmic_data; i++)
		msm_spm_drv_flush_shadow(dev, i);

	mb();

	for (i = 0; i < MSM_SPM_REG_SAW_PMIC_DATA_0 + num_pmic_data; i++)
		msm_spm_drv_load_shadow(dev, i);

@@ -608,26 +608,15 @@ void msm_spm_drv_reinit(struct msm_spm_driver_data *dev)
		msm_spm_drv_load_shadow(dev, i);
}

int msm_spm_drv_init(struct msm_spm_driver_data *dev,
int msm_spm_drv_reg_init(struct msm_spm_driver_data *dev,
		struct msm_spm_platform_data *data)
{
	int i;
	int num_spm_entry;
	bool found = false;

	BUG_ON(!dev || !data);

	dev->vctl_port = data->vctl_port;
	dev->phase_port = data->phase_port;
	dev->pfm_port = data->pfm_port;
	dev->ver_reg = data->ver_reg;
	dev->reg_base_addr = data->reg_base_addr;
	memcpy(dev->reg_shadow, data->reg_init_values,
			sizeof(data->reg_init_values));

	dev->vctl_timeout_us = data->vctl_timeout_us;

	msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);

	for (i = 0; i < ARRAY_SIZE(saw2_info); i++)
		if (dev->major == saw2_info[i].major &&
			dev->minor == saw2_info[i].minor) {
@@ -642,6 +631,34 @@ int msm_spm_drv_init(struct msm_spm_driver_data *dev,
		pr_err("%s: No SAW version found\n", __func__);
		BUG_ON(!found);
	}
	return 0;
}

void msm_spm_drv_upd_reg_shadow(struct msm_spm_driver_data *dev, int id,
		int val)
{
	dev->reg_shadow[id] = val;
	msm_spm_drv_flush_shadow(dev, id);
	/* Complete the above writes before other accesses */
	mb();
}

int msm_spm_drv_init(struct msm_spm_driver_data *dev,
		struct msm_spm_platform_data *data)
{
	int num_spm_entry;

	BUG_ON(!dev || !data);

	dev->vctl_port = data->vctl_port;
	dev->phase_port = data->phase_port;
	dev->pfm_port = data->pfm_port;
	dev->reg_base_addr = data->reg_base_addr;
	memcpy(dev->reg_shadow, data->reg_init_values,
			sizeof(data->reg_init_values));

	dev->vctl_timeout_us = data->vctl_timeout_us;


	if (!num_pmic_data)
		num_pmic_data = msm_spm_drv_get_num_pmic_data(dev);
+15 −7
Original line number Diff line number Diff line
@@ -250,6 +250,9 @@ static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
	if (!dev->initialized)
		return -ENXIO;

	if (!dev->num_modes)
		return 0;

	if (mode == MSM_SPM_MODE_DISABLED) {
		ret = msm_spm_drv_set_spm_enable(&dev->reg_data, false);
	} else if (!msm_spm_drv_set_spm_enable(&dev->reg_data, true)) {
@@ -288,7 +291,6 @@ static int msm_spm_dev_init(struct msm_spm_device *dev,
	if (!dev->modes)
		goto spm_failed_malloc;

	dev->reg_data.ver_reg = data->ver_reg;
	ret = msm_spm_drv_init(&dev->reg_data, data);

	if (ret)
@@ -308,7 +310,9 @@ static int msm_spm_dev_init(struct msm_spm_device *dev,

		dev->modes[i].mode = data->modes[i].mode;
	}
	msm_spm_drv_reinit(&dev->reg_data);

	msm_spm_drv_reinit(&dev->reg_data, dev->num_modes ? true : false);

	dev->initialized = true;

	return 0;
@@ -374,7 +378,8 @@ void msm_spm_reinit(void)
{
	unsigned int cpu;
	for_each_possible_cpu(cpu)
		msm_spm_drv_reinit(&per_cpu(msm_cpu_spm_device.reg_data, cpu));
		msm_spm_drv_reinit(
			&per_cpu(msm_cpu_spm_device.reg_data, cpu), true);
}
EXPORT_SYMBOL(msm_spm_reinit);

@@ -841,12 +846,14 @@ static int msm_spm_dev_probe(struct platform_device *pdev)
	 * SPM_LEGACY_MODE bit.
	 */
	msm_spm_config_q2s(dev, MSM_SPM_MODE_POWER_COLLAPSE);
	msm_spm_drv_reg_init(&dev->reg_data, &spm_data);

	for (i = 0; i < ARRAY_SIZE(spm_of_data); i++) {
		ret = of_property_read_u32(node, spm_of_data[i].key, &val);
		if (ret)
			continue;
		spm_data.reg_init_values[spm_of_data[i].id] = val;
		msm_spm_drv_upd_reg_shadow(&dev->reg_data, spm_of_data[i].id,
				val);
	}

	for_each_child_of_node(node, n) {
@@ -861,7 +868,6 @@ static int msm_spm_dev_probe(struct platform_device *pdev)
		if (ret)
			continue;

		pr_err("label name %s\n", name);
		for (i = 0; i < ARRAY_SIZE(mode_of_data); i++)
			if (!strcmp(name, mode_of_data[i].key))
					break;
@@ -909,13 +915,16 @@ static int msm_spm_dev_probe(struct platform_device *pdev)

	ret = msm_spm_dev_init(dev, &spm_data);
	if (ret)
		goto fail;
		pr_err("SPM modes programming is not available from HLOS\n");

	platform_set_drvdata(pdev, dev);

	for_each_cpu(cpu, &dev->mask)
		per_cpu(cpu_vctl_device, cpu) = dev;

	if (!spm_data.num_modes)
		return 0;

	cpu = get_cpu_id(pdev->dev.of_node);

	/* For CPUs that are online, the SPM has to be programmed for
@@ -927,7 +936,6 @@ static int msm_spm_dev_probe(struct platform_device *pdev)
		msm_spm_config_low_power_mode(dev, MSM_SPM_MODE_CLOCK_GATING,
				false);
	put_online_cpus();

	return ret;

fail:
+5 −2
Original line number Diff line number Diff line
@@ -96,7 +96,9 @@ struct msm_spm_driver_data {

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_reg_init(struct msm_spm_driver_data *dev,
		struct msm_spm_platform_data *data);
void msm_spm_drv_reinit(struct msm_spm_driver_data *dev, bool seq);
int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
		uint32_t ctl);
int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
@@ -126,5 +128,6 @@ int msm_spm_drv_avs_clear_irq(struct msm_spm_driver_data *dev,

void msm_spm_reinit(void);
int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);

void msm_spm_drv_upd_reg_shadow(struct msm_spm_driver_data *dev, int id,
		int val);
#endif