All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lina Iyer <lina.iyer@linaro.org>
To: daniel.lezcano@linaro.org, khilman@linaro.org,
	sboyd@codeaurora.org, davidb@codeaurora.org,
	galak@codeaurora.org, linux-arm-msm@vger.kernel.org,
	lorenzo.pieralisi@arm.com
Cc: msivasub@codeauorora.org, Lina Iyer <lina.iyer@linaro.org>,
	Praveen Chidamabram <pchidamb@codeaurora.org>,
	Murali Nalajala <mnalajal@codeaurora.org>
Subject: [PATCH v3 4/8] qcom: spm-devices: Add SPM device manager for the SoC
Date: Mon, 18 Aug 2014 16:23:30 -0600	[thread overview]
Message-ID: <1408400614-45419-5-git-send-email-lina.iyer@linaro.org> (raw)
In-Reply-To: <1408400614-45419-1-git-send-email-lina.iyer@linaro.org>

Each cpu or an L2$ has an SPM device. They are identical instances of
the same SPM block. This allows for multiple instances be grouped and
managed collectively. spm-devices.c is the SPM device manager managing
multiple SPM devices on top of the driver layer.

Device configuration of each SPM is picked up from the DTS. The hardware
configuration of each of the SPM is handled by the spm.c driver.

Signed-off-by: Praveen Chidamabram <pchidamb@codeaurora.org>
Signed-off-by: Murali Nalajala <mnalajal@codeaurora.org>
Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
---
 Documentation/devicetree/bindings/arm/msm/spm.txt |  47 +++++
 drivers/soc/qcom/Kconfig                          |   8 +
 drivers/soc/qcom/Makefile                         |   2 +-
 drivers/soc/qcom/spm-devices.c                    | 242 ++++++++++++++++++++++
 include/soc/qcom/spm.h                            |  34 +++
 5 files changed, 332 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/arm/msm/spm.txt
 create mode 100644 drivers/soc/qcom/spm-devices.c
 create mode 100644 include/soc/qcom/spm.h

diff --git a/Documentation/devicetree/bindings/arm/msm/spm.txt b/Documentation/devicetree/bindings/arm/msm/spm.txt
new file mode 100644
index 0000000..318e024
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/spm.txt
@@ -0,0 +1,47 @@
+* Subsystem Power Manager (SAW2)
+
+S4 generation of MSMs have SPM hardware blocks to control the Application
+Processor Sub-System power. These SPM blocks run individual state machine
+to determine what the core (L2 or Krait/Scorpion) would do when the WFI
+instruction is executed by the core.
+
+The devicetree representation of the SPM block should be:
+
+Required properties
+
+- compatible: Could be one of -
+		"qcom,spm-v2.1"
+		"qcom,spm-v3.0"
+- reg: The physical address and the size of the SPM's memory mapped registers
+- qcom,cpu: phandle for the CPU that the SPM block is attached to.
+	This field is required on only for SPMs that control the CPU.
+- qcom,saw2-cfg: SAW2 configuration register
+- qcom,saw2-spm-dly: Provides the values for the SPM delay command in the SPM
+	sequence
+- qcom,saw2-spm-ctl: The SPM control register
+
+Optional properties
+
+- qcom,saw2-spm-cmd-wfi: The WFI command sequence
+- qcom,saw2-spm-cmd-ret: The Retention command sequence
+- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
+- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence. This sequence may
+	turn off other SoC components.
+- qcom,saw2-spm-cmd-gdhs: GDHS (Globally Distributed Head Switch) command
+	sequence. This sequence will retain the memory but turn off the logic.
+-
+Example:
+	spm@f9089000 {
+		compatible = "qcom,spm-v2.1";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0xf9089000 0x1000>;
+		qcom,cpu = <&CPU0>;
+		qcom,saw2-cfg = <0x1>;
+		qcom,saw2-spm-dly= <0x20000400>;
+		qcom,saw2-spm-ctl = <0x1>;
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [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];
+	};
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 7dcd554..1569410 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -11,3 +11,11 @@ config QCOM_GSBI
 
 config QCOM_SCM
 	bool
+
+config QCOM_PM
+	tristate "Qualcomm Power Management"
+	depends on PM && ARCH_QCOM && OF
+	help
+	  QCOM Platform specific power driver to manage cores and L2 low power
+	  modes. It interface with various system drivers to put the cores in
+	  low power modes.
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 20b329f..9457b2a 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
-obj-$(CONFIG_QCOM_PM)	+=	spm.o
+obj-$(CONFIG_QCOM_PM)	+=	spm.o spm-devices.o
 CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
 obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o
diff --git a/drivers/soc/qcom/spm-devices.c b/drivers/soc/qcom/spm-devices.c
new file mode 100644
index 0000000..4f725f8
--- /dev/null
+++ b/drivers/soc/qcom/spm-devices.c
@@ -0,0 +1,242 @@
+/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <soc/qcom/spm.h>
+
+#include "spm_driver.h"
+
+
+struct msm_spm_power_modes {
+	uint32_t mode;
+	uint32_t start_addr;
+};
+
+struct msm_spm_device {
+	bool initialized;
+	struct msm_spm_driver_data reg_data;
+	struct msm_spm_power_modes *modes;
+	uint32_t num_modes;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_spm_device, msm_cpu_spm_device);
+
+/**
+ * msm_spm_set_low_power_mode() - Configure SPM start address for low power mode
+ * @mode: SPM LPM mode to enter
+ */
+int msm_spm_set_low_power_mode(unsigned int mode)
+{
+	struct msm_spm_device *dev = &__get_cpu_var(msm_cpu_spm_device);
+	uint32_t i;
+	uint32_t start_addr = 0;
+	int ret = -EINVAL;
+
+	if (!dev->initialized)
+		return -ENXIO;
+
+	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)) {
+		for (i = 0; i < dev->num_modes; i++) {
+			if (dev->modes[i].mode == mode) {
+				start_addr = dev->modes[i].start_addr;
+				break;
+			}
+		}
+		ret = msm_spm_drv_set_low_power_mode(&dev->reg_data,
+					start_addr);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(msm_spm_set_low_power_mode);
+
+static int get_cpu_id(struct device_node *node)
+{
+	struct device_node *cpu_node;
+	u32 cpu;
+	int ret = -EINVAL;
+	char *key = "qcom,cpu";
+
+	cpu_node = of_parse_phandle(node, key, 0);
+	if (cpu_node) {
+		for_each_possible_cpu(cpu) {
+			if (of_get_cpu_node(cpu, NULL) == cpu_node)
+				return cpu;
+		}
+	}
+	return ret;
+}
+
+static struct msm_spm_device *msm_spm_get_device(struct platform_device *pdev)
+{
+	struct msm_spm_device *dev = NULL;
+	int cpu = get_cpu_id(pdev->dev.of_node);
+
+	if ((cpu >= 0) && cpu < num_possible_cpus())
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
+
+	return dev;
+}
+
+static int msm_spm_dev_init(struct msm_spm_device *dev,
+		struct msm_spm_platform_data *data)
+{
+	int i;
+	int ret = -ENOMEM;
+	uint32_t offset = 0;
+
+	dev->num_modes = data->num_modes;
+	dev->modes = kcalloc(dev->num_modes,
+				sizeof(struct msm_spm_power_modes),
+				GFP_KERNEL);
+	if (!dev->modes)
+		return ret;
+
+	ret = msm_spm_drv_init(&dev->reg_data, data);
+	if (ret) {
+		kfree(dev->modes);
+		return ret;
+	}
+
+	for (i = 0; i < dev->num_modes; i++) {
+		dev->modes[i].start_addr = offset;
+		dev->modes[i].mode = data->modes[i].mode;
+		msm_spm_drv_write_seq_data(&dev->reg_data, data->modes[i].cmd,
+						&offset);
+	}
+
+	msm_spm_drv_reinit(&dev->reg_data);
+	dev->initialized = true;
+
+	return 0;
+}
+
+static int msm_spm_dev_probe(struct platform_device *pdev)
+{
+	int ret;
+	int i;
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_spm_platform_data spm_data;
+	char *key;
+	uint32_t val;
+	struct msm_spm_seq_entry modes[MSM_SPM_MODE_NR];
+	struct msm_spm_device *dev;
+	struct resource *res;
+	uint32_t mode_count = 0;
+
+	struct spm_of {
+		char *key;
+		uint32_t id;
+	};
+
+	/* SPM Configuration registers */
+	struct spm_of spm_of_data[] = {
+		{"qcom,saw2-clk-div", MSM_SPM_REG_SAW2_CFG},
+		{"qcom,saw2-enable", MSM_SPM_REG_SAW2_SPM_CTL},
+		{"qcom,saw2-delays", MSM_SPM_REG_SAW2_SPM_DLY},
+	};
+
+	/* SPM sleep sequences */
+	struct spm_of mode_of_data[] = {
+		{"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING},
+		{"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE},
+		{"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_RETENTION},
+	};
+
+	 /* Get the right SPM device */
+	dev = msm_spm_get_device(pdev);
+	if (IS_ERR_OR_NULL(dev))
+		return -EINVAL;
+
+	memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
+	memset(&modes, 0,
+		(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
+
+	/* Get the SAW start address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto fail;
+	}
+	spm_data.reg_base_addr = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!spm_data.reg_base_addr) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	/* Read the SPM configuration register values */
+	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;
+	}
+
+	/* Read the byte arrays for the SPM sleep sequences */
+	for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+		key = mode_of_data[i].key;
+		modes[mode_count].cmd =
+			(uint8_t *)of_get_property(node, key, &val);
+		if (!modes[mode_count].cmd)
+			continue;
+		modes[mode_count].mode = mode_of_data[i].id;
+		mode_count++;
+	}
+	spm_data.modes = modes;
+	spm_data.num_modes = mode_count;
+
+	/* Initialize the hardware */
+	ret = msm_spm_dev_init(dev, &spm_data);
+	if (ret)
+		goto fail;
+
+	platform_set_drvdata(pdev, dev);
+	return ret;
+
+fail:
+	dev_err(&pdev->dev, "SPM device probe failed: %d\n", ret);
+	return ret;
+}
+
+static struct of_device_id msm_spm_match_table[] = {
+	{.compatible = "qcom,spm-v2.1"},
+	{},
+};
+
+static struct platform_driver msm_spm_device_driver = {
+	.probe = msm_spm_dev_probe,
+	.driver = {
+		.name = "spm-v2",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_spm_match_table,
+	},
+};
+
+static int __init msm_spm_device_init(void)
+{
+	return platform_driver_register(&msm_spm_device_driver);
+}
+device_initcall(msm_spm_device_init);
diff --git a/include/soc/qcom/spm.h b/include/soc/qcom/spm.h
new file mode 100644
index 0000000..99a1d12
--- /dev/null
+++ b/include/soc/qcom/spm.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_SPM_H
+#define __QCOM_SPM_H
+
+enum {
+	MSM_SPM_MODE_DISABLED,
+	MSM_SPM_MODE_CLOCK_GATING,
+	MSM_SPM_MODE_RETENTION,
+	MSM_SPM_MODE_GDHS,
+	MSM_SPM_MODE_POWER_COLLAPSE,
+	MSM_SPM_MODE_NR
+};
+
+struct msm_spm_device;
+
+#if defined(CONFIG_QCOM_PM)
+int msm_spm_set_low_power_mode(unsigned int mode);
+#else /* defined(CONFIG_QCOM_PM) */
+static inline int msm_spm_set_low_power_mode(unsigned int mode)
+{ return -ENOSYS; }
+#endif  /* defined (CONFIG_QCOM_PM) */
+
+#endif  /* __QCOM_SPM_H */
-- 
1.9.1

  parent reply	other threads:[~2014-08-18 22:23 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-18 22:23 [PATCH v3 0/8] QCOM 8074 cpuidle driver Lina Iyer
2014-08-18 22:23 ` [PATCH v3 1/8] msm: scm: Move scm-boot files to drivers/soc and include/soc Lina Iyer
2014-08-27 17:18   ` Kevin Hilman
2014-08-27 18:57     ` Lina Iyer
2014-08-27 20:24       ` Kevin Hilman
2014-08-27 20:31         ` Lina Iyer
2014-08-18 22:23 ` [PATCH v3 2/8] msm: scm: Add SCM warmboot flags for quad core targets Lina Iyer
2014-08-18 22:23 ` [PATCH v3 3/8] qcom: spm: Add Subsystem Power Manager driver (SAW2) Lina Iyer
2014-08-19 14:07   ` Kumar Gala
2014-08-19 15:28     ` Lina Iyer
2014-08-18 22:23 ` Lina Iyer [this message]
2014-08-19  9:29   ` [PATCH v3 4/8] qcom: spm-devices: Add SPM device manager for the SoC Pramod Gurav
2014-08-19 14:51     ` Lina Iyer
2014-08-18 22:23 ` [PATCH v3 5/8] arm: dts: qcom: Add SPM device bindings for 8974 Lina Iyer
2014-08-18 22:23 ` [PATCH v3 6/8] qcom: msm-pm: Add cpu low power mode functions Lina Iyer
2014-08-18 22:23 ` [PATCH v3 7/8] qcom: cpuidle: Add cpuidle driver for QCOM cpus Lina Iyer
2014-08-19  7:41   ` Pramod Gurav
2014-08-19 14:54     ` Lina Iyer
2014-08-19 15:01       ` Pramod Gurav
2014-08-18 22:23 ` [PATCH v3 8/8] arm: dts: qcom: Add idle states device nodes for 8974 Lina Iyer
2014-08-19 15:30 ` [PATCH v3 0/8] QCOM 8074 cpuidle driver Lina Iyer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1408400614-45419-5-git-send-email-lina.iyer@linaro.org \
    --to=lina.iyer@linaro.org \
    --cc=daniel.lezcano@linaro.org \
    --cc=davidb@codeaurora.org \
    --cc=galak@codeaurora.org \
    --cc=khilman@linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=lorenzo.pieralisi@arm.com \
    --cc=mnalajal@codeaurora.org \
    --cc=msivasub@codeauorora.org \
    --cc=pchidamb@codeaurora.org \
    --cc=sboyd@codeaurora.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.