Initial commit
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
From 2bd25a6b5b5af59a33c22c2bf2cc4ea3043f33c5 Mon Sep 17 00:00:00 2001
|
||||
From: Ran Wang <ran.wang_1@nxp.com>
|
||||
Date: Thu, 24 Oct 2019 16:39:30 +0800
|
||||
Subject: [PATCH] soc: fsl: add RCPM driver
|
||||
|
||||
The NXP's QorIQ processors based on ARM Core have RCPM module
|
||||
(Run Control and Power Management), which performs system level
|
||||
tasks associated with power management such as wakeup source control.
|
||||
|
||||
Note that this driver will not support PowerPC based QorIQ processors,
|
||||
and it depends on PM wakeup source framework which provide collect
|
||||
wake information.
|
||||
|
||||
Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
|
||||
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
[rebase]
|
||||
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
|
||||
---
|
||||
drivers/soc/fsl/Kconfig | 9 +++
|
||||
drivers/soc/fsl/Makefile | 1 +
|
||||
drivers/soc/fsl/rcpm.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 161 insertions(+)
|
||||
create mode 100644 drivers/soc/fsl/rcpm.c
|
||||
|
||||
--- a/drivers/soc/fsl/Kconfig
|
||||
+++ b/drivers/soc/fsl/Kconfig
|
||||
@@ -52,4 +52,13 @@ config FSL_QIXIS
|
||||
Say y here to enable QIXIS system controller api. The qixis driver
|
||||
provides FPGA functions to control system.
|
||||
|
||||
+config FSL_RCPM
|
||||
+ bool "Freescale RCPM support"
|
||||
+ depends on PM_SLEEP && (ARM || ARM64)
|
||||
+ help
|
||||
+ The NXP QorIQ Processors based on ARM Core have RCPM module
|
||||
+ (Run Control and Power Management), which performs all device-level
|
||||
+ tasks associated with power management, such as wakeup source control.
|
||||
+ Note that currently this driver will not support PowerPC based
|
||||
+ QorIQ processor.
|
||||
endmenu
|
||||
--- a/drivers/soc/fsl/Makefile
|
||||
+++ b/drivers/soc/fsl/Makefile
|
||||
@@ -10,3 +10,4 @@ obj-$(CONFIG_FSL_QIXIS) += qixis_ctrl.
|
||||
obj-$(CONFIG_FSL_GUTS) += guts.o
|
||||
obj-$(CONFIG_FSL_MC_DPIO) += dpio/
|
||||
obj-$(CONFIG_DPAA2_CONSOLE) += dpaa2-console.o
|
||||
+obj-$(CONFIG_FSL_RCPM) += rcpm.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/soc/fsl/rcpm.c
|
||||
@@ -0,0 +1,151 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+//
|
||||
+// rcpm.c - Freescale QorIQ RCPM driver
|
||||
+//
|
||||
+// Copyright 2019 NXP
|
||||
+//
|
||||
+// Author: Ran Wang <ran.wang_1@nxp.com>
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/suspend.h>
|
||||
+#include <linux/kernel.h>
|
||||
+
|
||||
+#define RCPM_WAKEUP_CELL_MAX_SIZE 7
|
||||
+
|
||||
+struct rcpm {
|
||||
+ unsigned int wakeup_cells;
|
||||
+ void __iomem *ippdexpcr_base;
|
||||
+ bool little_endian;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * rcpm_pm_prepare - performs device-level tasks associated with power
|
||||
+ * management, such as programming related to the wakeup source control.
|
||||
+ * @dev: Device to handle.
|
||||
+ *
|
||||
+ */
|
||||
+static int rcpm_pm_prepare(struct device *dev)
|
||||
+{
|
||||
+ int i, ret, idx;
|
||||
+ void __iomem *base;
|
||||
+ struct wakeup_source *ws;
|
||||
+ struct rcpm *rcpm;
|
||||
+ struct device_node *np = dev->of_node;
|
||||
+ u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1];
|
||||
+ u32 setting[RCPM_WAKEUP_CELL_MAX_SIZE] = {0};
|
||||
+
|
||||
+ rcpm = dev_get_drvdata(dev);
|
||||
+ if (!rcpm)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ base = rcpm->ippdexpcr_base;
|
||||
+ idx = wakeup_sources_read_lock();
|
||||
+
|
||||
+ /* Begin with first registered wakeup source */
|
||||
+ for_each_wakeup_source(ws) {
|
||||
+
|
||||
+ /* skip object which is not attached to device */
|
||||
+ if (!ws->dev || !ws->dev->parent)
|
||||
+ continue;
|
||||
+
|
||||
+ ret = device_property_read_u32_array(ws->dev->parent,
|
||||
+ "fsl,rcpm-wakeup", value,
|
||||
+ rcpm->wakeup_cells + 1);
|
||||
+
|
||||
+ /* Wakeup source should refer to current rcpm device */
|
||||
+ if (ret || (np->phandle != value[0]))
|
||||
+ continue;
|
||||
+
|
||||
+ /* Property "#fsl,rcpm-wakeup-cells" of rcpm node defines the
|
||||
+ * number of IPPDEXPCR register cells, and "fsl,rcpm-wakeup"
|
||||
+ * of wakeup source IP contains an integer array: <phandle to
|
||||
+ * RCPM node, IPPDEXPCR0 setting, IPPDEXPCR1 setting,
|
||||
+ * IPPDEXPCR2 setting, etc>.
|
||||
+ *
|
||||
+ * So we will go thought them to collect setting data.
|
||||
+ */
|
||||
+ for (i = 0; i < rcpm->wakeup_cells; i++)
|
||||
+ setting[i] |= value[i + 1];
|
||||
+ }
|
||||
+
|
||||
+ wakeup_sources_read_unlock(idx);
|
||||
+
|
||||
+ /* Program all IPPDEXPCRn once */
|
||||
+ for (i = 0; i < rcpm->wakeup_cells; i++) {
|
||||
+ u32 tmp = setting[i];
|
||||
+ void __iomem *address = base + i * 4;
|
||||
+
|
||||
+ if (!tmp)
|
||||
+ continue;
|
||||
+
|
||||
+ /* We can only OR related bits */
|
||||
+ if (rcpm->little_endian) {
|
||||
+ tmp |= ioread32(address);
|
||||
+ iowrite32(tmp, address);
|
||||
+ } else {
|
||||
+ tmp |= ioread32be(address);
|
||||
+ iowrite32be(tmp, address);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct dev_pm_ops rcpm_pm_ops = {
|
||||
+ .prepare = rcpm_pm_prepare,
|
||||
+};
|
||||
+
|
||||
+static int rcpm_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct resource *r;
|
||||
+ struct rcpm *rcpm;
|
||||
+ int ret;
|
||||
+
|
||||
+ rcpm = devm_kzalloc(dev, sizeof(*rcpm), GFP_KERNEL);
|
||||
+ if (!rcpm)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (!r)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ rcpm->ippdexpcr_base = devm_ioremap_resource(&pdev->dev, r);
|
||||
+ if (IS_ERR(rcpm->ippdexpcr_base)) {
|
||||
+ ret = PTR_ERR(rcpm->ippdexpcr_base);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ rcpm->little_endian = device_property_read_bool(
|
||||
+ &pdev->dev, "little-endian");
|
||||
+
|
||||
+ ret = device_property_read_u32(&pdev->dev,
|
||||
+ "#fsl,rcpm-wakeup-cells", &rcpm->wakeup_cells);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ dev_set_drvdata(&pdev->dev, rcpm);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id rcpm_of_match[] = {
|
||||
+ { .compatible = "fsl,qoriq-rcpm-2.1+", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rcpm_of_match);
|
||||
+
|
||||
+static struct platform_driver rcpm_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "rcpm",
|
||||
+ .of_match_table = rcpm_of_match,
|
||||
+ .pm = &rcpm_pm_ops,
|
||||
+ },
|
||||
+ .probe = rcpm_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(rcpm_driver);
|
||||
Reference in New Issue
Block a user