aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch201
1 files changed, 201 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch b/target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch
new file mode 100644
index 0000000000..533534d7c9
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/813-pm-0001-soc-fsl-add-RCPM-driver.patch
@@ -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);