From: Nishanth Menon <nm@ti.com>
To: Kevin Hilman <khilman@kernel.org>,
"Rafael J. Wysocki" <rjw@rjwysocki.net>,
Ulf Hansson <ulf.hansson@linaro.org>
Cc: Dave Gerlach <d-gerlach@ti.com>, Keerthy <j-keerthy@ti.com>,
Peter Ujfalusi <peter.ujfalusi@ti.com>,
Tero Kristo <t-kristo@ti.com>,
Russell King <rmk+kernel@armlinux.org.uk>,
Sudeep Holla <sudeep.holla@arm.com>,
Santosh Shilimkar <ssantosh@kernel.org>,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org,
Nishanth Menon <nm@ti.com>
Subject: [PATCH 3/3] soc: ti: Add ti_sci_pm_domains driver
Date: Fri, 19 Aug 2016 18:56:53 -0500 [thread overview]
Message-ID: <20160819235653.26355-4-nm@ti.com> (raw)
In-Reply-To: <20160819235653.26355-1-nm@ti.com>
From: Dave Gerlach <d-gerlach@ti.com>
Introduce a ti_sci_pm_domains to act as a generic pm domain provider to
allow each device to map into it's own genpd and be controlled through
the TI SCI protocol.
This driver implements a onecell genpd where each device node will have
a phandle to the power domain node and an index which represents the ID
to be passed with TI SCI representing the device. Through this interface
the power_on and power_off hooks within the driver will use TI SCI to
turn on and off hardware blocks as determined by pm_runtime usage.
This includes contributions by Andrew F. Davis <afd@ti.com>
Signed-off-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
---
MAINTAINERS | 1 +
arch/arm/mach-keystone/Kconfig | 1 +
drivers/soc/ti/Kconfig | 12 ++
drivers/soc/ti/Makefile | 1 +
drivers/soc/ti/ti_sci_pm_domains.c | 222 +++++++++++++++++++++++++++++++++++++
5 files changed, 237 insertions(+)
create mode 100644 drivers/soc/ti/ti_sci_pm_domains.c
diff --git a/MAINTAINERS b/MAINTAINERS
index ea14b08c30bb..448f6801bd78 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11575,6 +11575,7 @@ F: drivers/firmware/ti_sci*
F: include/linux/soc/ti/ti_sci_protocol.h
F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
F: include/dt-bindings/genpd/k2g.h
+F: drivers/soc/ti/ti_sci_pm_domains.c
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
index 8ff61be1a29f..34ef4b60adc6 100644
--- a/arch/arm/mach-keystone/Kconfig
+++ b/arch/arm/mach-keystone/Kconfig
@@ -11,6 +11,7 @@ config ARCH_KEYSTONE
select MIGHT_HAVE_PCI
select PCI_DOMAINS if PCI
select PINCTRL
+ select PM_GENERIC_DOMAINS if PM
help
Support for boards based on the Texas Instruments Keystone family of
SoCs.
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index 3557c5e32a93..39e152abe6b9 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -38,4 +38,16 @@ config WKUP_M3_IPC
to communicate and use the Wakeup M3 for PM features like suspend
resume and boots it using wkup_m3_rproc driver.
+config TI_SCI_PM_DOMAINS
+ tristate "TI SCI PM Domains Driver"
+ depends on TI_SCI_PROTOCOL
+ depends on PM_GENERIC_DOMAINS
+ help
+ Generic power domain implementation for TI device implementing
+ the TI SCI protocol.
+
+ To compile this as a module, choose M here. The module will be
+ called ti_sci_pm_domains. Note this is needed early in boot before
+ rootfs may be available.
+
endif # SOC_TI
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 48ff3a79634f..7d572736c86e 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o
knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
+obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
diff --git a/drivers/soc/ti/ti_sci_pm_domains.c b/drivers/soc/ti/ti_sci_pm_domains.c
new file mode 100644
index 000000000000..ab6b20201731
--- /dev/null
+++ b/drivers/soc/ti/ti_sci_pm_domains.c
@@ -0,0 +1,222 @@
+/*
+ * TI SCI Generic Power Domain Driver
+ *
+ * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ * Dave Gerlach <d-gerlach@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+#define TI_GENPD_NAME_LENGTH 16
+
+/**
+ * struct ti_sci_genpd_data: holds data needed for every power domain
+ * @ti_sci: handle to TI SCI protocol driver that provides ops to
+ * communicate with system control processor.
+ * @dev: pointer to dev for the driver for devm allocs
+ * @pd_list_mutex: Mutex for protecting the global list of power domains
+ * @pd_list: list that hols all power domains as they are allocated
+ */
+struct ti_sci_genpd_data {
+ const struct ti_sci_handle *ti_sci;
+ struct device *dev;
+ struct mutex pd_list_mutex; /* Protect master list of domains */
+ struct list_head pd_list;
+};
+
+/**
+ * struct ti_sci_pm_domain: TI specific data needed for each power domain
+ * @idx: index of the power domain that identifies it with the system
+ * control processor.
+ * @pd: generic_pm_domain for use with the genpd framework
+ * @node: list_head for tracking all domains in a list
+ * @parent: pointer to the global data defined for all domains
+ */
+struct ti_sci_pm_domain {
+ int idx;
+ struct generic_pm_domain pd;
+ struct list_head node;
+ struct ti_sci_genpd_data *parent;
+};
+
+#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
+
+/**
+ * pd_power_off(): generic_pm_domain power_off hook
+ * @domain: generic_pm_domain struct provided by genpd framework of the
+ * pd to be shut off
+ *
+ * This hook uses the put_device dev_op provided by ti_sci to power off the
+ * device associated to the power domain provided.
+ */
+static int pd_power_off(struct generic_pm_domain *domain)
+{
+ struct ti_sci_pm_domain *ti_sci_pd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = ti_sci_pd->parent->ti_sci;
+
+ return ti_sci->ops.dev_ops.put_device(ti_sci,
+ ti_sci_pd->idx);
+}
+
+/**
+ * pd_power_on(): generic_pm_domain power_on hook
+ * @domain: generic_pm_domain struct provided by genpd framework of the
+ * pd to be powered on
+ *
+ * This hook uses the get_device dev_op provided by ti_sci to power on the
+ * device associated to the power domain provided.
+ */
+static int pd_power_on(struct generic_pm_domain *domain)
+{
+ struct ti_sci_pm_domain *ti_sci_pd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = ti_sci_pd->parent->ti_sci;
+
+ return ti_sci->ops.dev_ops.get_device(ti_sci,
+ ti_sci_pd->idx);
+}
+
+/**
+ * of_ti_sci_genpd_xlate_onecell() - Xlate function using a single index.
+ * @genpdspec: OF phandle args to define an index to be communicated over
+ * TI SCI to the system control processor to identify it
+ * @data: xlate function private data - pointer to the ti_sci_genpd_data
+ * struct containing global sci pm domain data
+ *
+ * This is xlate function takes a single cell as an index representing the
+ * id to be passed to the system control processor. As each device in the
+ * device tree probes a single pm domain will be created specifically for it
+ * based on the index passed in the pweor-domains property. If no pm domain
+ * yet exists for that index it is created, otherwise it is looked up and
+ * returned. Through this 1 to 1 association between power domains and
+ * devices the genpd framework will work to directly control devices
+ * through the pm_runtime framework.
+ */
+static struct generic_pm_domain *of_ti_sci_genpd_xlate_onecell(
+ struct of_phandle_args *genpdspec,
+ void *data)
+{
+ struct ti_sci_genpd_data *ti_sci_genpd = data;
+ const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
+ struct device *dev = ti_sci_genpd->dev;
+ unsigned int idx = genpdspec->args[0];
+ struct ti_sci_pm_domain *ti_sci_pd = NULL, *pd;
+ char *name;
+ int ret = 0;
+
+ if (genpdspec->args_count != 1)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Check the validity of the requested idx, if the index is not valid
+ * the PMMC will return a NAK here and we will not allocate it.
+ */
+ ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&ti_sci_genpd->pd_list_mutex);
+ list_for_each_entry(pd, &ti_sci_genpd->pd_list, node) {
+ if (pd->idx == idx) {
+ ti_sci_pd = pd;
+ goto unlock_and_return;
+ }
+ }
+
+ ti_sci_pd = devm_kzalloc(dev,
+ sizeof(*ti_sci_pd),
+ GFP_KERNEL);
+ if (!ti_sci_pd) {
+ ret = -ENOMEM;
+ goto unlock_and_return;
+ }
+
+ ti_sci_pd->idx = idx;
+ ti_sci_pd->pd.power_off = pd_power_off;
+ ti_sci_pd->pd.power_on = pd_power_on;
+
+ name = devm_kzalloc(dev, TI_GENPD_NAME_LENGTH, GFP_KERNEL);
+ if (!name) {
+ devm_kfree(dev, ti_sci_pd);
+ ret = -ENOMEM;
+ goto unlock_and_return;
+ }
+
+ snprintf(name, TI_GENPD_NAME_LENGTH, "pd-%d", idx);
+ ti_sci_pd->pd.name = name;
+
+ ti_sci_pd->parent = ti_sci_genpd;
+ /*
+ * Init each pd as is_off so we always call pd_power_on
+ * to make sure reference counting is properly maintained
+ * on the SCI side
+ */
+ pm_genpd_init(&ti_sci_pd->pd, NULL, true);
+
+ list_add(&ti_sci_pd->node, &ti_sci_genpd->pd_list);
+
+unlock_and_return:
+ mutex_unlock(&ti_sci_genpd->pd_list_mutex);
+
+ if (ret)
+ return ERR_PTR(ret);
+ else
+ return &ti_sci_pd->pd;
+}
+
+static const struct of_device_id ti_sci_pm_domain_matches[] = {
+ { .compatible = "ti,sci-pm-domains", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
+
+static int ti_sci_pm_domains_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ti_sci_genpd_data *ti_sci_genpd;
+
+ ti_sci_genpd = devm_kzalloc(dev, sizeof(*ti_sci_genpd), GFP_KERNEL);
+ if (!ti_sci_genpd)
+ return -ENOMEM;
+
+ ti_sci_genpd->ti_sci = devm_ti_sci_get_handle(dev);
+ if (IS_ERR(ti_sci_genpd->ti_sci))
+ return PTR_ERR(ti_sci_genpd->ti_sci);
+
+ ti_sci_genpd->dev = dev;
+
+ INIT_LIST_HEAD(&ti_sci_genpd->pd_list);
+ mutex_init(&ti_sci_genpd->pd_list_mutex);
+
+ return __of_genpd_add_provider(np, of_ti_sci_genpd_xlate_onecell,
+ ti_sci_genpd);
+}
+
+static struct platform_driver ti_sci_pm_domains_driver = {
+ .probe = ti_sci_pm_domains_probe,
+ .driver = {
+ .name = "ti_sci_pm_domains",
+ .of_match_table = ti_sci_pm_domain_matches,
+ },
+};
+module_platform_driver(ti_sci_pm_domains_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI System Control Interface(SCI) Power Domain driver");
+MODULE_AUTHOR("Dave Gerlach");
--
2.9.1.200.gb1ec08f
WARNING: multiple messages have this Message-ID (diff)
From: nm@ti.com (Nishanth Menon)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 3/3] soc: ti: Add ti_sci_pm_domains driver
Date: Fri, 19 Aug 2016 18:56:53 -0500 [thread overview]
Message-ID: <20160819235653.26355-4-nm@ti.com> (raw)
In-Reply-To: <20160819235653.26355-1-nm@ti.com>
From: Dave Gerlach <d-gerlach@ti.com>
Introduce a ti_sci_pm_domains to act as a generic pm domain provider to
allow each device to map into it's own genpd and be controlled through
the TI SCI protocol.
This driver implements a onecell genpd where each device node will have
a phandle to the power domain node and an index which represents the ID
to be passed with TI SCI representing the device. Through this interface
the power_on and power_off hooks within the driver will use TI SCI to
turn on and off hardware blocks as determined by pm_runtime usage.
This includes contributions by Andrew F. Davis <afd@ti.com>
Signed-off-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
---
MAINTAINERS | 1 +
arch/arm/mach-keystone/Kconfig | 1 +
drivers/soc/ti/Kconfig | 12 ++
drivers/soc/ti/Makefile | 1 +
drivers/soc/ti/ti_sci_pm_domains.c | 222 +++++++++++++++++++++++++++++++++++++
5 files changed, 237 insertions(+)
create mode 100644 drivers/soc/ti/ti_sci_pm_domains.c
diff --git a/MAINTAINERS b/MAINTAINERS
index ea14b08c30bb..448f6801bd78 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11575,6 +11575,7 @@ F: drivers/firmware/ti_sci*
F: include/linux/soc/ti/ti_sci_protocol.h
F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
F: include/dt-bindings/genpd/k2g.h
+F: drivers/soc/ti/ti_sci_pm_domains.c
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
index 8ff61be1a29f..34ef4b60adc6 100644
--- a/arch/arm/mach-keystone/Kconfig
+++ b/arch/arm/mach-keystone/Kconfig
@@ -11,6 +11,7 @@ config ARCH_KEYSTONE
select MIGHT_HAVE_PCI
select PCI_DOMAINS if PCI
select PINCTRL
+ select PM_GENERIC_DOMAINS if PM
help
Support for boards based on the Texas Instruments Keystone family of
SoCs.
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index 3557c5e32a93..39e152abe6b9 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -38,4 +38,16 @@ config WKUP_M3_IPC
to communicate and use the Wakeup M3 for PM features like suspend
resume and boots it using wkup_m3_rproc driver.
+config TI_SCI_PM_DOMAINS
+ tristate "TI SCI PM Domains Driver"
+ depends on TI_SCI_PROTOCOL
+ depends on PM_GENERIC_DOMAINS
+ help
+ Generic power domain implementation for TI device implementing
+ the TI SCI protocol.
+
+ To compile this as a module, choose M here. The module will be
+ called ti_sci_pm_domains. Note this is needed early in boot before
+ rootfs may be available.
+
endif # SOC_TI
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 48ff3a79634f..7d572736c86e 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o
knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
+obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
diff --git a/drivers/soc/ti/ti_sci_pm_domains.c b/drivers/soc/ti/ti_sci_pm_domains.c
new file mode 100644
index 000000000000..ab6b20201731
--- /dev/null
+++ b/drivers/soc/ti/ti_sci_pm_domains.c
@@ -0,0 +1,222 @@
+/*
+ * TI SCI Generic Power Domain Driver
+ *
+ * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ * Dave Gerlach <d-gerlach@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+#define TI_GENPD_NAME_LENGTH 16
+
+/**
+ * struct ti_sci_genpd_data: holds data needed for every power domain
+ * @ti_sci: handle to TI SCI protocol driver that provides ops to
+ * communicate with system control processor.
+ * @dev: pointer to dev for the driver for devm allocs
+ * @pd_list_mutex: Mutex for protecting the global list of power domains
+ * @pd_list: list that hols all power domains as they are allocated
+ */
+struct ti_sci_genpd_data {
+ const struct ti_sci_handle *ti_sci;
+ struct device *dev;
+ struct mutex pd_list_mutex; /* Protect master list of domains */
+ struct list_head pd_list;
+};
+
+/**
+ * struct ti_sci_pm_domain: TI specific data needed for each power domain
+ * @idx: index of the power domain that identifies it with the system
+ * control processor.
+ * @pd: generic_pm_domain for use with the genpd framework
+ * @node: list_head for tracking all domains in a list
+ * @parent: pointer to the global data defined for all domains
+ */
+struct ti_sci_pm_domain {
+ int idx;
+ struct generic_pm_domain pd;
+ struct list_head node;
+ struct ti_sci_genpd_data *parent;
+};
+
+#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
+
+/**
+ * pd_power_off(): generic_pm_domain power_off hook
+ * @domain: generic_pm_domain struct provided by genpd framework of the
+ * pd to be shut off
+ *
+ * This hook uses the put_device dev_op provided by ti_sci to power off the
+ * device associated to the power domain provided.
+ */
+static int pd_power_off(struct generic_pm_domain *domain)
+{
+ struct ti_sci_pm_domain *ti_sci_pd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = ti_sci_pd->parent->ti_sci;
+
+ return ti_sci->ops.dev_ops.put_device(ti_sci,
+ ti_sci_pd->idx);
+}
+
+/**
+ * pd_power_on(): generic_pm_domain power_on hook
+ * @domain: generic_pm_domain struct provided by genpd framework of the
+ * pd to be powered on
+ *
+ * This hook uses the get_device dev_op provided by ti_sci to power on the
+ * device associated to the power domain provided.
+ */
+static int pd_power_on(struct generic_pm_domain *domain)
+{
+ struct ti_sci_pm_domain *ti_sci_pd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = ti_sci_pd->parent->ti_sci;
+
+ return ti_sci->ops.dev_ops.get_device(ti_sci,
+ ti_sci_pd->idx);
+}
+
+/**
+ * of_ti_sci_genpd_xlate_onecell() - Xlate function using a single index.
+ * @genpdspec: OF phandle args to define an index to be communicated over
+ * TI SCI to the system control processor to identify it
+ * @data: xlate function private data - pointer to the ti_sci_genpd_data
+ * struct containing global sci pm domain data
+ *
+ * This is xlate function takes a single cell as an index representing the
+ * id to be passed to the system control processor. As each device in the
+ * device tree probes a single pm domain will be created specifically for it
+ * based on the index passed in the pweor-domains property. If no pm domain
+ * yet exists for that index it is created, otherwise it is looked up and
+ * returned. Through this 1 to 1 association between power domains and
+ * devices the genpd framework will work to directly control devices
+ * through the pm_runtime framework.
+ */
+static struct generic_pm_domain *of_ti_sci_genpd_xlate_onecell(
+ struct of_phandle_args *genpdspec,
+ void *data)
+{
+ struct ti_sci_genpd_data *ti_sci_genpd = data;
+ const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
+ struct device *dev = ti_sci_genpd->dev;
+ unsigned int idx = genpdspec->args[0];
+ struct ti_sci_pm_domain *ti_sci_pd = NULL, *pd;
+ char *name;
+ int ret = 0;
+
+ if (genpdspec->args_count != 1)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Check the validity of the requested idx, if the index is not valid
+ * the PMMC will return a NAK here and we will not allocate it.
+ */
+ ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&ti_sci_genpd->pd_list_mutex);
+ list_for_each_entry(pd, &ti_sci_genpd->pd_list, node) {
+ if (pd->idx == idx) {
+ ti_sci_pd = pd;
+ goto unlock_and_return;
+ }
+ }
+
+ ti_sci_pd = devm_kzalloc(dev,
+ sizeof(*ti_sci_pd),
+ GFP_KERNEL);
+ if (!ti_sci_pd) {
+ ret = -ENOMEM;
+ goto unlock_and_return;
+ }
+
+ ti_sci_pd->idx = idx;
+ ti_sci_pd->pd.power_off = pd_power_off;
+ ti_sci_pd->pd.power_on = pd_power_on;
+
+ name = devm_kzalloc(dev, TI_GENPD_NAME_LENGTH, GFP_KERNEL);
+ if (!name) {
+ devm_kfree(dev, ti_sci_pd);
+ ret = -ENOMEM;
+ goto unlock_and_return;
+ }
+
+ snprintf(name, TI_GENPD_NAME_LENGTH, "pd-%d", idx);
+ ti_sci_pd->pd.name = name;
+
+ ti_sci_pd->parent = ti_sci_genpd;
+ /*
+ * Init each pd as is_off so we always call pd_power_on
+ * to make sure reference counting is properly maintained
+ * on the SCI side
+ */
+ pm_genpd_init(&ti_sci_pd->pd, NULL, true);
+
+ list_add(&ti_sci_pd->node, &ti_sci_genpd->pd_list);
+
+unlock_and_return:
+ mutex_unlock(&ti_sci_genpd->pd_list_mutex);
+
+ if (ret)
+ return ERR_PTR(ret);
+ else
+ return &ti_sci_pd->pd;
+}
+
+static const struct of_device_id ti_sci_pm_domain_matches[] = {
+ { .compatible = "ti,sci-pm-domains", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
+
+static int ti_sci_pm_domains_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ti_sci_genpd_data *ti_sci_genpd;
+
+ ti_sci_genpd = devm_kzalloc(dev, sizeof(*ti_sci_genpd), GFP_KERNEL);
+ if (!ti_sci_genpd)
+ return -ENOMEM;
+
+ ti_sci_genpd->ti_sci = devm_ti_sci_get_handle(dev);
+ if (IS_ERR(ti_sci_genpd->ti_sci))
+ return PTR_ERR(ti_sci_genpd->ti_sci);
+
+ ti_sci_genpd->dev = dev;
+
+ INIT_LIST_HEAD(&ti_sci_genpd->pd_list);
+ mutex_init(&ti_sci_genpd->pd_list_mutex);
+
+ return __of_genpd_add_provider(np, of_ti_sci_genpd_xlate_onecell,
+ ti_sci_genpd);
+}
+
+static struct platform_driver ti_sci_pm_domains_driver = {
+ .probe = ti_sci_pm_domains_probe,
+ .driver = {
+ .name = "ti_sci_pm_domains",
+ .of_match_table = ti_sci_pm_domain_matches,
+ },
+};
+module_platform_driver(ti_sci_pm_domains_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI System Control Interface(SCI) Power Domain driver");
+MODULE_AUTHOR("Dave Gerlach");
--
2.9.1.200.gb1ec08f
WARNING: multiple messages have this Message-ID (diff)
From: Nishanth Menon <nm@ti.com>
To: Kevin Hilman <khilman@kernel.org>,
"Rafael J. Wysocki" <rjw@rjwysocki.net>,
Ulf Hansson <ulf.hansson@linaro.org>
Cc: Dave Gerlach <d-gerlach@ti.com>, Keerthy <j-keerthy@ti.com>,
Peter Ujfalusi <peter.ujfalusi@ti.com>,
Tero Kristo <t-kristo@ti.com>,
Russell King <rmk+kernel@armlinux.org.uk>,
Sudeep Holla <sudeep.holla@arm.com>,
Santosh Shilimkar <ssantosh@kernel.org>,
<linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<linux-pm@vger.kernel.org>, Nishanth Menon <nm@ti.com>
Subject: [PATCH 3/3] soc: ti: Add ti_sci_pm_domains driver
Date: Fri, 19 Aug 2016 18:56:53 -0500 [thread overview]
Message-ID: <20160819235653.26355-4-nm@ti.com> (raw)
In-Reply-To: <20160819235653.26355-1-nm@ti.com>
From: Dave Gerlach <d-gerlach@ti.com>
Introduce a ti_sci_pm_domains to act as a generic pm domain provider to
allow each device to map into it's own genpd and be controlled through
the TI SCI protocol.
This driver implements a onecell genpd where each device node will have
a phandle to the power domain node and an index which represents the ID
to be passed with TI SCI representing the device. Through this interface
the power_on and power_off hooks within the driver will use TI SCI to
turn on and off hardware blocks as determined by pm_runtime usage.
This includes contributions by Andrew F. Davis <afd@ti.com>
Signed-off-by: Keerthy <j-keerthy@ti.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
---
MAINTAINERS | 1 +
arch/arm/mach-keystone/Kconfig | 1 +
drivers/soc/ti/Kconfig | 12 ++
drivers/soc/ti/Makefile | 1 +
drivers/soc/ti/ti_sci_pm_domains.c | 222 +++++++++++++++++++++++++++++++++++++
5 files changed, 237 insertions(+)
create mode 100644 drivers/soc/ti/ti_sci_pm_domains.c
diff --git a/MAINTAINERS b/MAINTAINERS
index ea14b08c30bb..448f6801bd78 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11575,6 +11575,7 @@ F: drivers/firmware/ti_sci*
F: include/linux/soc/ti/ti_sci_protocol.h
F: Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
F: include/dt-bindings/genpd/k2g.h
+F: drivers/soc/ti/ti_sci_pm_domains.c
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
index 8ff61be1a29f..34ef4b60adc6 100644
--- a/arch/arm/mach-keystone/Kconfig
+++ b/arch/arm/mach-keystone/Kconfig
@@ -11,6 +11,7 @@ config ARCH_KEYSTONE
select MIGHT_HAVE_PCI
select PCI_DOMAINS if PCI
select PINCTRL
+ select PM_GENERIC_DOMAINS if PM
help
Support for boards based on the Texas Instruments Keystone family of
SoCs.
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
index 3557c5e32a93..39e152abe6b9 100644
--- a/drivers/soc/ti/Kconfig
+++ b/drivers/soc/ti/Kconfig
@@ -38,4 +38,16 @@ config WKUP_M3_IPC
to communicate and use the Wakeup M3 for PM features like suspend
resume and boots it using wkup_m3_rproc driver.
+config TI_SCI_PM_DOMAINS
+ tristate "TI SCI PM Domains Driver"
+ depends on TI_SCI_PROTOCOL
+ depends on PM_GENERIC_DOMAINS
+ help
+ Generic power domain implementation for TI device implementing
+ the TI SCI protocol.
+
+ To compile this as a module, choose M here. The module will be
+ called ti_sci_pm_domains. Note this is needed early in boot before
+ rootfs may be available.
+
endif # SOC_TI
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 48ff3a79634f..7d572736c86e 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o
knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
obj-$(CONFIG_WKUP_M3_IPC) += wkup_m3_ipc.o
+obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
diff --git a/drivers/soc/ti/ti_sci_pm_domains.c b/drivers/soc/ti/ti_sci_pm_domains.c
new file mode 100644
index 000000000000..ab6b20201731
--- /dev/null
+++ b/drivers/soc/ti/ti_sci_pm_domains.c
@@ -0,0 +1,222 @@
+/*
+ * TI SCI Generic Power Domain Driver
+ *
+ * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ * Dave Gerlach <d-gerlach@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+
+#define TI_GENPD_NAME_LENGTH 16
+
+/**
+ * struct ti_sci_genpd_data: holds data needed for every power domain
+ * @ti_sci: handle to TI SCI protocol driver that provides ops to
+ * communicate with system control processor.
+ * @dev: pointer to dev for the driver for devm allocs
+ * @pd_list_mutex: Mutex for protecting the global list of power domains
+ * @pd_list: list that hols all power domains as they are allocated
+ */
+struct ti_sci_genpd_data {
+ const struct ti_sci_handle *ti_sci;
+ struct device *dev;
+ struct mutex pd_list_mutex; /* Protect master list of domains */
+ struct list_head pd_list;
+};
+
+/**
+ * struct ti_sci_pm_domain: TI specific data needed for each power domain
+ * @idx: index of the power domain that identifies it with the system
+ * control processor.
+ * @pd: generic_pm_domain for use with the genpd framework
+ * @node: list_head for tracking all domains in a list
+ * @parent: pointer to the global data defined for all domains
+ */
+struct ti_sci_pm_domain {
+ int idx;
+ struct generic_pm_domain pd;
+ struct list_head node;
+ struct ti_sci_genpd_data *parent;
+};
+
+#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
+
+/**
+ * pd_power_off(): generic_pm_domain power_off hook
+ * @domain: generic_pm_domain struct provided by genpd framework of the
+ * pd to be shut off
+ *
+ * This hook uses the put_device dev_op provided by ti_sci to power off the
+ * device associated to the power domain provided.
+ */
+static int pd_power_off(struct generic_pm_domain *domain)
+{
+ struct ti_sci_pm_domain *ti_sci_pd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = ti_sci_pd->parent->ti_sci;
+
+ return ti_sci->ops.dev_ops.put_device(ti_sci,
+ ti_sci_pd->idx);
+}
+
+/**
+ * pd_power_on(): generic_pm_domain power_on hook
+ * @domain: generic_pm_domain struct provided by genpd framework of the
+ * pd to be powered on
+ *
+ * This hook uses the get_device dev_op provided by ti_sci to power on the
+ * device associated to the power domain provided.
+ */
+static int pd_power_on(struct generic_pm_domain *domain)
+{
+ struct ti_sci_pm_domain *ti_sci_pd = genpd_to_ti_sci_pd(domain);
+ const struct ti_sci_handle *ti_sci = ti_sci_pd->parent->ti_sci;
+
+ return ti_sci->ops.dev_ops.get_device(ti_sci,
+ ti_sci_pd->idx);
+}
+
+/**
+ * of_ti_sci_genpd_xlate_onecell() - Xlate function using a single index.
+ * @genpdspec: OF phandle args to define an index to be communicated over
+ * TI SCI to the system control processor to identify it
+ * @data: xlate function private data - pointer to the ti_sci_genpd_data
+ * struct containing global sci pm domain data
+ *
+ * This is xlate function takes a single cell as an index representing the
+ * id to be passed to the system control processor. As each device in the
+ * device tree probes a single pm domain will be created specifically for it
+ * based on the index passed in the pweor-domains property. If no pm domain
+ * yet exists for that index it is created, otherwise it is looked up and
+ * returned. Through this 1 to 1 association between power domains and
+ * devices the genpd framework will work to directly control devices
+ * through the pm_runtime framework.
+ */
+static struct generic_pm_domain *of_ti_sci_genpd_xlate_onecell(
+ struct of_phandle_args *genpdspec,
+ void *data)
+{
+ struct ti_sci_genpd_data *ti_sci_genpd = data;
+ const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
+ struct device *dev = ti_sci_genpd->dev;
+ unsigned int idx = genpdspec->args[0];
+ struct ti_sci_pm_domain *ti_sci_pd = NULL, *pd;
+ char *name;
+ int ret = 0;
+
+ if (genpdspec->args_count != 1)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Check the validity of the requested idx, if the index is not valid
+ * the PMMC will return a NAK here and we will not allocate it.
+ */
+ ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&ti_sci_genpd->pd_list_mutex);
+ list_for_each_entry(pd, &ti_sci_genpd->pd_list, node) {
+ if (pd->idx == idx) {
+ ti_sci_pd = pd;
+ goto unlock_and_return;
+ }
+ }
+
+ ti_sci_pd = devm_kzalloc(dev,
+ sizeof(*ti_sci_pd),
+ GFP_KERNEL);
+ if (!ti_sci_pd) {
+ ret = -ENOMEM;
+ goto unlock_and_return;
+ }
+
+ ti_sci_pd->idx = idx;
+ ti_sci_pd->pd.power_off = pd_power_off;
+ ti_sci_pd->pd.power_on = pd_power_on;
+
+ name = devm_kzalloc(dev, TI_GENPD_NAME_LENGTH, GFP_KERNEL);
+ if (!name) {
+ devm_kfree(dev, ti_sci_pd);
+ ret = -ENOMEM;
+ goto unlock_and_return;
+ }
+
+ snprintf(name, TI_GENPD_NAME_LENGTH, "pd-%d", idx);
+ ti_sci_pd->pd.name = name;
+
+ ti_sci_pd->parent = ti_sci_genpd;
+ /*
+ * Init each pd as is_off so we always call pd_power_on
+ * to make sure reference counting is properly maintained
+ * on the SCI side
+ */
+ pm_genpd_init(&ti_sci_pd->pd, NULL, true);
+
+ list_add(&ti_sci_pd->node, &ti_sci_genpd->pd_list);
+
+unlock_and_return:
+ mutex_unlock(&ti_sci_genpd->pd_list_mutex);
+
+ if (ret)
+ return ERR_PTR(ret);
+ else
+ return &ti_sci_pd->pd;
+}
+
+static const struct of_device_id ti_sci_pm_domain_matches[] = {
+ { .compatible = "ti,sci-pm-domains", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
+
+static int ti_sci_pm_domains_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct ti_sci_genpd_data *ti_sci_genpd;
+
+ ti_sci_genpd = devm_kzalloc(dev, sizeof(*ti_sci_genpd), GFP_KERNEL);
+ if (!ti_sci_genpd)
+ return -ENOMEM;
+
+ ti_sci_genpd->ti_sci = devm_ti_sci_get_handle(dev);
+ if (IS_ERR(ti_sci_genpd->ti_sci))
+ return PTR_ERR(ti_sci_genpd->ti_sci);
+
+ ti_sci_genpd->dev = dev;
+
+ INIT_LIST_HEAD(&ti_sci_genpd->pd_list);
+ mutex_init(&ti_sci_genpd->pd_list_mutex);
+
+ return __of_genpd_add_provider(np, of_ti_sci_genpd_xlate_onecell,
+ ti_sci_genpd);
+}
+
+static struct platform_driver ti_sci_pm_domains_driver = {
+ .probe = ti_sci_pm_domains_probe,
+ .driver = {
+ .name = "ti_sci_pm_domains",
+ .of_match_table = ti_sci_pm_domain_matches,
+ },
+};
+module_platform_driver(ti_sci_pm_domains_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI System Control Interface(SCI) Power Domain driver");
+MODULE_AUTHOR("Dave Gerlach");
--
2.9.1.200.gb1ec08f
next prev parent reply other threads:[~2016-08-19 23:56 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-19 23:56 [PATCH 0/3] ARM: K2G: Add support for TI-SCI Generic PM Domains Nishanth Menon
2016-08-19 23:56 ` Nishanth Menon
2016-08-19 23:56 ` Nishanth Menon
2016-08-19 23:56 ` [PATCH 1/3] Documentation: dt: Add TI-SCI " Nishanth Menon
2016-08-19 23:56 ` Nishanth Menon
2016-08-19 23:56 ` Nishanth Menon
[not found] ` <20160819235653.26355-2-nm-l0cyMroinI0@public.gmane.org>
2016-09-02 14:31 ` Rob Herring
2016-09-02 14:31 ` Rob Herring
2016-09-02 14:31 ` Rob Herring
[not found] ` <20160819235653.26355-1-nm-l0cyMroinI0@public.gmane.org>
2016-08-19 23:56 ` [PATCH 2/3] dt-bindings: genpd: Add K2G device definitions Nishanth Menon
2016-08-19 23:56 ` Nishanth Menon
2016-08-19 23:56 ` Nishanth Menon
2016-08-25 7:32 ` Ulf Hansson
2016-08-25 7:32 ` Ulf Hansson
2016-08-19 23:56 ` Nishanth Menon [this message]
2016-08-19 23:56 ` [PATCH 3/3] soc: ti: Add ti_sci_pm_domains driver Nishanth Menon
2016-08-19 23:56 ` Nishanth Menon
2016-08-25 7:27 ` Ulf Hansson
2016-08-25 7:27 ` Ulf Hansson
2016-08-25 7:27 ` Ulf Hansson
[not found] ` <CAPDyKFooDUOPT9dP8HaW3YBO9PsX-1+96PPE7CRMyjEkra7cBQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-08-26 23:37 ` Dave Gerlach
2016-08-26 23:37 ` Dave Gerlach
2016-08-26 23:37 ` Dave Gerlach
[not found] ` <57C0D2C9.1030801-l0cyMroinI0@public.gmane.org>
2016-08-30 19:43 ` Dave Gerlach
2016-08-30 19:43 ` Dave Gerlach
2016-08-30 19:43 ` Dave Gerlach
2016-08-30 20:26 ` Ulf Hansson
2016-08-30 20:26 ` Ulf Hansson
2016-09-06 20:28 ` Dave Gerlach
2016-09-06 20:28 ` Dave Gerlach
2016-09-07 18:38 ` Kevin Hilman
2016-09-07 18:38 ` Kevin Hilman
2016-09-07 18:38 ` Kevin Hilman
2016-09-08 9:27 ` Ulf Hansson
2016-09-08 9:27 ` Ulf Hansson
2016-09-08 17:38 ` Kevin Hilman
2016-09-08 17:38 ` Kevin Hilman
2016-09-08 17:38 ` Kevin Hilman
2016-09-08 18:04 ` Dave Gerlach
2016-09-08 18:04 ` Dave Gerlach
2016-09-09 8:34 ` Ulf Hansson
2016-09-09 8:34 ` Ulf Hansson
[not found] ` <57CF26DB.4020807-l0cyMroinI0@public.gmane.org>
2016-09-08 9:18 ` Ulf Hansson
2016-09-08 9:18 ` Ulf Hansson
2016-09-08 9:18 ` Ulf Hansson
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=20160819235653.26355-4-nm@ti.com \
--to=nm@ti.com \
--cc=d-gerlach@ti.com \
--cc=devicetree@vger.kernel.org \
--cc=j-keerthy@ti.com \
--cc=khilman@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=peter.ujfalusi@ti.com \
--cc=rjw@rjwysocki.net \
--cc=rmk+kernel@armlinux.org.uk \
--cc=ssantosh@kernel.org \
--cc=sudeep.holla@arm.com \
--cc=t-kristo@ti.com \
--cc=ulf.hansson@linaro.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.