This is a patch series for cpuidle driver for Sunplus SP7021 SoC.
Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates
many peripherals (ex: UART, I2C, SPI, SDIO, eMMC, USB, SD card and
etc.) into a single chip. It is designed for industrial control.
Refer to:
https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
https://tibbo.com/store/plus1.html
Edwin Chiu (2):
dt-bingings:arm:sunplus:add sp7021 compatible string to
sunplus,idle-state.yaml
cpuidle:sunplus:create cpuidle driver for sunplus sp7021
.../bindings/arm/sunplus/sunplus,idle-state.yaml | 59 ++++++++
MAINTAINERS | 9 ++
drivers/cpuidle/Kconfig.arm | 7 +
drivers/cpuidle/Makefile | 1 +
drivers/cpuidle/cpuidle-sunplus.c | 167 +++++++++++++++++++++
include/linux/platform_data/cpuidle-sunplus.h | 19 +++
6 files changed, 262 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
create mode 100644 drivers/cpuidle/cpuidle-sunplus.c
create mode 100644 include/linux/platform_data/cpuidle-sunplus.h
--
2.7.4
Add the compatible string for cpuidle state on sp7021
Signed-off-by: Edwin Chiu <[email protected]>
---
Changes in v3
- Align email address of sob and sender
- Added sp7021 compatible string
.../bindings/arm/sunplus/sunplus,idle-state.yaml | 59 ++++++++++++++++++++++
MAINTAINERS | 5 ++
2 files changed, 64 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
diff --git a/Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml b/Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
new file mode 100644
index 0000000..64281ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/sunplus/sunplus,idle-state.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SOC cpuidle state
+
+maintainers:
+ - Edwin Chiu<[email protected]>
+
+description: |
+ Sunplus SOC cpuidle state
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - sunplus,sp7021-idle-state
+
+ entry-latency-us:
+ description:
+ Worst case latency in microseconds required to enter the idle state.
+
+ exit-latency-us:
+ description:
+ Worst case latency in microseconds required to exit the idle state.
+ The exit-latency-us duration may be guaranteed only after
+ entry-latency-us has passed.
+
+ min-residency-us:
+ description:
+ Minimum residency duration in microseconds, inclusive of preparation
+ and entry, for this idle state to be considered worthwhile energy wise
+ (refer to section 2 of this document for a complete description).
+
+required:
+ - compatible
+ - entry-latency-us
+ - exit-latency-us
+ - min-residency-us
+
+additionalProperties: true
+
+examples:
+ - |
+
+ idle-state {
+ CPU_IDLE: cpu_idle {
+ compatible = "sunplus,sp7021-idle-state";
+ entry-latency-us = <8000>;
+ exit-latency-us = <700>;
+ min-residency-us = <9000>;
+ };
+ };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index e0dca8f..22cfafe 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18252,6 +18252,11 @@ L: [email protected]
S: Maintained
F: drivers/net/ethernet/dlink/sundance.c
+SUNPLUS CPUIDLE DRIVER
+M: Edwin Chiu <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
+
SUPERH
M: Yoshinori Sato <[email protected]>
M: Rich Felker <[email protected]>
--
2.7.4
Create cpuidle driver for sunplus sp7021 chip
Signed-off-by: Edwin Chiu <[email protected]>
---
Changes in v3
- Rearrangement #include sequence
- Change remark style to /*~*/
- Align author email address to same as sob
- Optimal code
MAINTAINERS | 4 +
drivers/cpuidle/Kconfig.arm | 7 ++
drivers/cpuidle/Makefile | 1 +
drivers/cpuidle/cpuidle-sunplus.c | 167 ++++++++++++++++++++++++++
include/linux/platform_data/cpuidle-sunplus.h | 19 +++
5 files changed, 198 insertions(+)
create mode 100644 drivers/cpuidle/cpuidle-sunplus.c
create mode 100644 include/linux/platform_data/cpuidle-sunplus.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 22cfafe..4fb5e5c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18256,6 +18256,10 @@ SUNPLUS CPUIDLE DRIVER
M: Edwin Chiu <[email protected]>
S: Maintained
F: Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
+F: drivers/cpuidle/Kconfig.arm
+F: drivers/cpuidle/Makefile
+F: drivers/cpuidle/cpuidle-sunplus.c
+F: include/linux/platform_data/cpuidle-sunplus.h
SUPERH
M: Yoshinori Sato <[email protected]>
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index 15d6c46..fd921c5 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -118,3 +118,10 @@ config ARM_QCOM_SPM_CPUIDLE
The Subsystem Power Manager (SPM) controls low power modes for the
CPU and L2 cores. It interface with various system drivers to put
the cores in low power modes.
+
+config ARM_SUNPLUS_CPUIDLE
+ bool "CPU Idle Driver For SUNPLUS SoCs"
+ depends on !ARM64
+ select DT_IDLE_STATES
+ help
+ Select this to enable cpuidle on SP7021 processors.
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 26bbc5e..0a020d1 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_ARM_PSCI_CPUIDLE) += cpuidle-psci.o
obj-$(CONFIG_ARM_PSCI_CPUIDLE_DOMAIN) += cpuidle-psci-domain.o
obj-$(CONFIG_ARM_TEGRA_CPUIDLE) += cpuidle-tegra.o
obj-$(CONFIG_ARM_QCOM_SPM_CPUIDLE) += cpuidle-qcom-spm.o
+obj-$(CONFIG_ARM_SUNPLUS_CPUIDLE) += cpuidle-sunplus.o
###############################################################################
# MIPS drivers
diff --git a/drivers/cpuidle/cpuidle-sunplus.c b/drivers/cpuidle/cpuidle-sunplus.c
new file mode 100644
index 0000000..0e7bf43
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-sunplus.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014,2015, Linaro Ltd.
+ *
+ * SAW power controller driver
+ */
+#define pr_fmt(fmt) "CPUidle arm: " fmt
+
+#include <asm/suspend.h>
+#include <linux/cpu_cooling.h>
+#include <linux/cpuidle.h>
+#include <linux/cpumask.h>
+#include <linux/cpu_pm.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/platform_data/cpuidle-sunplus.h>
+
+#include "dt_idle_states.h"
+
+static int sp7021_wfi_finisher(unsigned long flags)
+{
+ cpu_v7_do_idle(); /* idle to WFI */
+
+ return -1;
+}
+
+static int sp7021_enter_idle_state(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int idx)
+{
+ int ret;
+
+ /* if idx=0, call cpu_do_idle() */
+ if (!idx) {
+ cpu_v7_do_idle();
+ return idx;
+ }
+
+ /* if idx>0, call cpu_suspend() */
+ ret = cpu_pm_enter();
+ if (!ret) {
+ /*
+ * Pass idle state index to cpuidle_suspend which in turn
+ * will call the CPU ops suspend protocol with idle index as a
+ * parameter.
+ */
+ ret = cpu_suspend(idx, sp7021_wfi_finisher);
+ }
+ cpu_pm_exit();
+
+ return ret ? -1:idx;
+}
+
+static struct cpuidle_driver sp7021_idle_driver = {
+ .name = "sp7021_idle",
+ .owner = THIS_MODULE,
+ /*
+ * State at index 0 is standby wfi and considered standard
+ * on all ARM platforms. If in some platforms simple wfi
+ * can't be used as "state 0", DT bindings must be implemented
+ * to work around this issue and allow installing a special
+ * handler for idle state index 0.
+ */
+ .states[0] = {
+ .enter = sp7021_enter_idle_state,
+ .exit_latency = 1,
+ .target_residency = 1,
+ .power_usage = UINT_MAX,
+ .name = "WFI",
+ .desc = "ARM WFI",
+ }
+};
+
+static const struct of_device_id sp7021_idle_state_match[] = {
+ { .compatible = "sunplus,sp7021-idle-state",
+ .data = sp7021_enter_idle_state },
+ { },
+};
+
+/*
+ * sp7021_idle_init - Initializes sp7021 cpuidle driver
+ *
+ * Initializes sp7021 cpuidle driver for all CPUs, if any CPU fails
+ * to register cpuidle driver then rollback to cancel all CPUs
+ * registration.
+ */
+static int __init sp7021_idle_init(void)
+{
+ int cpu, ret;
+ struct cpuidle_driver *drv;
+ struct cpuidle_device *dev;
+
+ drv = kmemdup(&sp7021_idle_driver, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ drv->cpumask = (struct cpumask *)cpumask_of(cpu);
+ /*
+ * Initialize idle states data, starting at index 1. This
+ * driver is DT only, if no DT idle states are detected (ret
+ * == 0) let the driver initialization fail accordingly since
+ * there is no reason to initialize the idle driver if only
+ * wfi is supported.
+ */
+ ret = dt_init_idle_driver(drv, sp7021_idle_state_match, 1);
+ if (ret <= 0)
+ return ret ? : -ENODEV;
+
+ ret = cpuidle_register_driver(drv);
+ if (ret) {
+ pr_err("Failed to register cpuidle driver\n");
+ return ret;
+ }
+
+ for_each_possible_cpu(cpu) {
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto out_fail;
+ }
+ dev->cpu = cpu;
+
+ ret = cpuidle_register_device(dev);
+ if (ret) {
+ pr_err("Failed to register cpuidle device for CPU %d\n", cpu);
+ kfree(dev);
+ goto out_fail;
+ }
+ }
+
+ return 0;
+
+out_fail:
+ while (--cpu >= 0) {
+ dev = per_cpu(cpuidle_devices, cpu);
+ cpuidle_unregister_device(dev);
+ kfree(dev);
+ }
+ cpuidle_unregister_driver(drv);
+
+ return ret;
+}
+
+static int __init idle_init(void)
+{
+ int ret;
+
+ if (of_machine_is_compatible("sunplus,sp7021-achip")) {
+ sp7021_idle_init();
+ ret = 0;
+ } else
+ ret = -1;
+
+ if (ret) {
+ pr_err("failed to cpuidle init\n");
+ return ret;
+ }
+
+ return ret;
+}
+device_initcall(idle_init);
+
+MODULE_AUTHOR("Edwin Chiu <[email protected]>");
+MODULE_DESCRIPTION("Sunplus sp7021 cpuidle driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/cpuidle-sunplus.h b/include/linux/platform_data/cpuidle-sunplus.h
new file mode 100644
index 0000000..bf87682
--- /dev/null
+++ b/include/linux/platform_data/cpuidle-sunplus.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * 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.
+ */
+
+#ifndef __CPUIDLE_SP7021_H
+#define __CPUIDLE_SP7021_H
+
+struct cpuidle_sp7021_data {
+ int (*cpu23_powerdown)(void);
+ void (*pre_enter_aftr)(void);
+ void (*post_enter_aftr)(void);
+};
+
+extern int cpu_v7_do_idle(void);
+
+#endif
--
2.7.4
On Thu, Jan 06, 2022 at 10:00:07AM +0800, Edwin Chiu wrote:
> Add the compatible string for cpuidle state on sp7021
>
> Signed-off-by: Edwin Chiu <[email protected]>
> ---
> Changes in v3
> - Align email address of sob and sender
> - Added sp7021 compatible string
>
> .../bindings/arm/sunplus/sunplus,idle-state.yaml | 59 ++++++++++++++++++++++
> MAINTAINERS | 5 ++
> 2 files changed, 64 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
>
> diff --git a/Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml b/Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
> new file mode 100644
> index 0000000..64281ba
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/sunplus/sunplus,idle-state.yaml
> @@ -0,0 +1,59 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (C) Sunplus Co., Ltd. 2021
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/arm/sunplus/sunplus,idle-state.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sunplus SOC cpuidle state
> +
> +maintainers:
> + - Edwin Chiu<[email protected]>
> +
> +description: |
> + Sunplus SOC cpuidle state
> +
> +properties:
> + compatible:
> + oneOf:
> + - items:
> + - enum:
> + - sunplus,sp7021-idle-state
> +
> + entry-latency-us:
> + description:
> + Worst case latency in microseconds required to enter the idle state.
> +
> + exit-latency-us:
> + description:
> + Worst case latency in microseconds required to exit the idle state.
> + The exit-latency-us duration may be guaranteed only after
> + entry-latency-us has passed.
> +
> + min-residency-us:
> + description:
> + Minimum residency duration in microseconds, inclusive of preparation
> + and entry, for this idle state to be considered worthwhile energy wise
> + (refer to section 2 of this document for a complete description).
> +
> +required:
> + - compatible
> + - entry-latency-us
> + - exit-latency-us
> + - min-residency-us
> +
> +additionalProperties: true
> +
> +examples:
> + - |
> +
> + idle-state {
> + CPU_IDLE: cpu_idle {
> + compatible = "sunplus,sp7021-idle-state";
> + entry-latency-us = <8000>;
> + exit-latency-us = <700>;
> + min-residency-us = <9000>;
> + };
> + };
Again, this is no different than the generic binding. There is no need
for this binding. Just wanting a different driver is not a reason for a
duplicate schema.
Rob