[V2] ARM: imx: add i.MX7ULP cpuidle support
diff mbox series

Message ID 1547185955-2395-1-git-send-email-Anson.Huang@nxp.com
State New
Headers show
Series
  • [V2] ARM: imx: add i.MX7ULP cpuidle support
Related show

Commit Message

Anson Huang Jan. 11, 2019, 5:57 a.m. UTC
This patch adds cpuidle support for i.MX7ULP, 3 cpuidle
states supported as below:

1. WFI, just ARM wfi;
2. WAIT mode, mapped to SoC's partial stop mode #3;
3. STOP mode, mapped to SoC's partial stop mode #1.

In WAIT mode, system clock and bus clock will be enabled;
In STOP mode, system clock and bus clock will be disabled.

Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
ChangeLog Since V1:
  - add prefix for power mode name;
  - use tab instead of spaces, sorry for this stupid mistake.
---
 arch/arm/mach-imx/Makefile          |  1 +
 arch/arm/mach-imx/common.h          | 10 +++++++
 arch/arm/mach-imx/cpuidle-imx7ulp.c | 60 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-imx/cpuidle.h         |  5 ++++
 arch/arm/mach-imx/mach-imx7ulp.c    |  7 +++++
 arch/arm/mach-imx/pm-imx7ulp.c      | 49 ++++++++++++++++++++++++++----
 6 files changed, 127 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/mach-imx/cpuidle-imx7ulp.c

Comments

Shawn Guo Jan. 14, 2019, 12:56 a.m. UTC | #1
On Fri, Jan 11, 2019 at 05:57:30AM +0000, Anson Huang wrote:
> This patch adds cpuidle support for i.MX7ULP, 3 cpuidle
> states supported as below:
> 
> 1. WFI, just ARM wfi;
> 2. WAIT mode, mapped to SoC's partial stop mode #3;
> 3. STOP mode, mapped to SoC's partial stop mode #1.
> 
> In WAIT mode, system clock and bus clock will be enabled;
> In STOP mode, system clock and bus clock will be disabled.
> 
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>

Applied, thanks.
Leonard Crestez Jan. 15, 2019, 12:30 p.m. UTC | #2
On 1/14/19 2:56 AM, Shawn Guo wrote:
> On Fri, Jan 11, 2019 at 05:57:30AM +0000, Anson Huang wrote:
> > This patch adds cpuidle support for i.MX7ULP, 3 cpuidle
> > states supported as below:
> > 
> > 1. WFI, just ARM wfi;
> > 2. WAIT mode, mapped to SoC's partial stop mode #3;
> > 3. STOP mode, mapped to SoC's partial stop mode #1.
> > 
> > In WAIT mode, system clock and bus clock will be enabled;
> > In STOP mode, system clock and bus clock will be disabled.
> > 
> > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> 
> Applied, thanks.
> 

Hello,

I'm not sure if anyone else already noticed but it seems the
arch/arm/mach-imx/cpuidle-imx7ulp.c file was dropped?

It's not in your tree:

https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git/commit/?h=imx/soc&id=cf2d2d392906f5603cf0d0f3630f6386babf7e4b

This causes build failures in next-20190115 with imx_v6_v7_defconfig.

--
Regards,
Leonard
Stephen Rothwell Jan. 15, 2019, 1:10 p.m. UTC | #3
Hi Leonard,

On Tue, 15 Jan 2019 12:30:23 +0000 Leonard Crestez <leonard.crestez@nxp.com> wrote:
>
> On 1/14/19 2:56 AM, Shawn Guo wrote:
> > On Fri, Jan 11, 2019 at 05:57:30AM +0000, Anson Huang wrote:  
> > > This patch adds cpuidle support for i.MX7ULP, 3 cpuidle
> > > states supported as below:
> > > 
> > > 1. WFI, just ARM wfi;
> > > 2. WAIT mode, mapped to SoC's partial stop mode #3;
> > > 3. STOP mode, mapped to SoC's partial stop mode #1.
> > > 
> > > In WAIT mode, system clock and bus clock will be enabled;
> > > In STOP mode, system clock and bus clock will be disabled.
> > > 
> > > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>  
> > 
> > Applied, thanks.
> >   
> 
> Hello,
> 
> I'm not sure if anyone else already noticed but it seems the
> arch/arm/mach-imx/cpuidle-imx7ulp.c file was dropped?
> 
> It's not in your tree:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git/commit/?h=imx/soc&id=cf2d2d392906f5603cf0d0f3630f6386babf7e4b
> 
> This causes build failures in next-20190115 with imx_v6_v7_defconfig.

That file does not exist in Linus' tree either.  And there are no
commits in linux-next that add it.
Shawn Guo Jan. 15, 2019, 3:12 p.m. UTC | #4
On Wed, Jan 16, 2019 at 12:10:43AM +1100, Stephen Rothwell wrote:
> Hi Leonard,
> 
> On Tue, 15 Jan 2019 12:30:23 +0000 Leonard Crestez <leonard.crestez@nxp.com> wrote:
> >
> > On 1/14/19 2:56 AM, Shawn Guo wrote:
> > > On Fri, Jan 11, 2019 at 05:57:30AM +0000, Anson Huang wrote:  
> > > > This patch adds cpuidle support for i.MX7ULP, 3 cpuidle
> > > > states supported as below:
> > > > 
> > > > 1. WFI, just ARM wfi;
> > > > 2. WAIT mode, mapped to SoC's partial stop mode #3;
> > > > 3. STOP mode, mapped to SoC's partial stop mode #1.
> > > > 
> > > > In WAIT mode, system clock and bus clock will be enabled;
> > > > In STOP mode, system clock and bus clock will be disabled.
> > > > 
> > > > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>  
> > > 
> > > Applied, thanks.
> > >   
> > 
> > Hello,
> > 
> > I'm not sure if anyone else already noticed but it seems the
> > arch/arm/mach-imx/cpuidle-imx7ulp.c file was dropped?
> > 
> > It's not in your tree:
> > 
> > https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git/commit/?h=imx/soc&id=cf2d2d392906f5603cf0d0f3630f6386babf7e4b
> > 
> > This causes build failures in next-20190115 with imx_v6_v7_defconfig.
> 
> That file does not exist in Linus' tree either.  And there are no
> commits in linux-next that add it.

Sorry.  That's my fault.  The patch doesn't apply to my tree and I had
to use 'patch' command.  However, I forgot to add this new
cpuidle-imx7ulp.c file.

Just fixed it.

Shawn

Patch
diff mbox series

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 8af2f7e..12aa44a 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -29,6 +29,7 @@  obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o
 obj-$(CONFIG_SOC_IMX6SLL) += cpuidle-imx6sx.o
 obj-$(CONFIG_SOC_IMX6SX) += cpuidle-imx6sx.o
 obj-$(CONFIG_SOC_IMX6UL) += cpuidle-imx6sx.o
+obj-$(CONFIG_SOC_IMX7ULP) += cpuidle-imx7ulp.o
 endif
 
 ifdef CONFIG_SND_IMX_SOC
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index bc915e5..c51764a 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -72,6 +72,15 @@  enum mxc_cpu_pwr_mode {
 	STOP_POWER_OFF,		/* STOP + SRPG */
 };
 
+enum ulp_cpu_pwr_mode {
+	ULP_PM_HSRUN,    /* High speed run mode */
+	ULP_PM_RUN,      /* Run mode */
+	ULP_PM_WAIT,     /* Wait mode */
+	ULP_PM_STOP,     /* Stop mode */
+	ULP_PM_VLPS,     /* Very low power stop mode */
+	ULP_PM_VLLS,     /* very low leakage stop mode */
+};
+
 void imx_enable_cpu(int cpu, bool enable);
 void imx_set_cpu_jump(int cpu, void *jump_addr);
 u32 imx_get_cpu_arg(int cpu);
@@ -98,6 +107,7 @@  int imx6_set_lpm(enum mxc_cpu_pwr_mode mode);
 void imx6_set_int_mem_clk_lpm(bool enable);
 void imx6sl_set_wait_clk(bool enter);
 int imx_mmdc_get_ddr_type(void);
+int imx7ulp_set_lpm(enum ulp_cpu_pwr_mode mode);
 
 void imx_cpu_die(unsigned int cpu);
 int imx_cpu_kill(unsigned int cpu);
diff --git a/arch/arm/mach-imx/cpuidle-imx7ulp.c b/arch/arm/mach-imx/cpuidle-imx7ulp.c
new file mode 100644
index 0000000..ca86c96
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx7ulp.c
@@ -0,0 +1,60 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *   Anson Huang <Anson.Huang@nxp.com>
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <asm/cpuidle.h>
+
+#include "common.h"
+#include "cpuidle.h"
+
+static int imx7ulp_enter_wait(struct cpuidle_device *dev,
+			    struct cpuidle_driver *drv, int index)
+{
+	if (index == 1)
+		imx7ulp_set_lpm(ULP_PM_WAIT);
+	else
+		imx7ulp_set_lpm(ULP_PM_STOP);
+
+	cpu_do_idle();
+
+	imx7ulp_set_lpm(ULP_PM_RUN);
+
+	return index;
+}
+
+static struct cpuidle_driver imx7ulp_cpuidle_driver = {
+	.name = "imx7ulp_cpuidle",
+	.owner = THIS_MODULE,
+	.states = {
+		/* WFI */
+		ARM_CPUIDLE_WFI_STATE,
+		/* WAIT */
+		{
+			.exit_latency = 50,
+			.target_residency = 75,
+			.enter = imx7ulp_enter_wait,
+			.name = "WAIT",
+			.desc = "PSTOP2",
+		},
+		/* STOP */
+		{
+			.exit_latency = 100,
+			.target_residency = 150,
+			.enter = imx7ulp_enter_wait,
+			.name = "STOP",
+			.desc = "PSTOP1",
+		},
+	},
+	.state_count = 3,
+	.safe_state_index = 0,
+};
+
+int __init imx7ulp_cpuidle_init(void)
+{
+	return cpuidle_register(&imx7ulp_cpuidle_driver, NULL);
+}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index f914012..7694c8f 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -15,6 +15,7 @@  extern int imx5_cpuidle_init(void);
 extern int imx6q_cpuidle_init(void);
 extern int imx6sl_cpuidle_init(void);
 extern int imx6sx_cpuidle_init(void);
+extern int imx7ulp_cpuidle_init(void);
 #else
 static inline int imx5_cpuidle_init(void)
 {
@@ -32,4 +33,8 @@  static inline int imx6sx_cpuidle_init(void)
 {
 	return 0;
 }
+static inline int imx7ulp_cpuidle_init(void)
+{
+	return 0;
+}
 #endif
diff --git a/arch/arm/mach-imx/mach-imx7ulp.c b/arch/arm/mach-imx/mach-imx7ulp.c
index 16b295b..11ac71a 100644
--- a/arch/arm/mach-imx/mach-imx7ulp.c
+++ b/arch/arm/mach-imx/mach-imx7ulp.c
@@ -12,6 +12,7 @@ 
 #include <asm/mach/arch.h>
 
 #include "common.h"
+#include "cpuidle.h"
 #include "hardware.h"
 
 #define SIM_JTAG_ID_REG		0x8c
@@ -64,7 +65,13 @@  static const char *const imx7ulp_dt_compat[] __initconst = {
 	NULL,
 };
 
+static void __init imx7ulp_init_late(void)
+{
+	imx7ulp_cpuidle_init();
+}
+
 DT_MACHINE_START(IMX7ulp, "Freescale i.MX7ULP (Device Tree)")
 	.init_machine	= imx7ulp_init_machine,
 	.dt_compat	= imx7ulp_dt_compat,
+	.init_late	= imx7ulp_init_late,
 MACHINE_END
diff --git a/arch/arm/mach-imx/pm-imx7ulp.c b/arch/arm/mach-imx/pm-imx7ulp.c
index cf6a380..7b2f738 100644
--- a/arch/arm/mach-imx/pm-imx7ulp.c
+++ b/arch/arm/mach-imx/pm-imx7ulp.c
@@ -9,21 +9,60 @@ 
 #include <linux/of.h>
 #include <linux/of_address.h>
 
+#include "common.h"
+
 #define SMC_PMCTRL		0x10
 #define BP_PMCTRL_PSTOPO        16
 #define PSTOPO_PSTOP3		0x3
+#define PSTOPO_PSTOP2		0x2
+#define PSTOPO_PSTOP1		0x1
+#define BP_PMCTRL_RUNM		8
+#define RUNM_RUN		0
+#define BP_PMCTRL_STOPM		0
+#define STOPM_STOP		0
+
+#define BM_PMCTRL_PSTOPO	(3 << BP_PMCTRL_PSTOPO)
+#define BM_PMCTRL_RUNM		(3 << BP_PMCTRL_RUNM)
+#define BM_PMCTRL_STOPM		(7 << BP_PMCTRL_STOPM)
+
+static void __iomem *smc1_base;
+
+int imx7ulp_set_lpm(enum ulp_cpu_pwr_mode mode)
+{
+	u32 val = readl_relaxed(smc1_base + SMC_PMCTRL);
+
+	/* clear all */
+	val &= ~(BM_PMCTRL_RUNM | BM_PMCTRL_STOPM | BM_PMCTRL_PSTOPO);
+
+	switch (mode) {
+	case ULP_PM_RUN:
+		/* system/bus clock enabled */
+		val |= PSTOPO_PSTOP3 << BP_PMCTRL_PSTOPO;
+		break;
+	case ULP_PM_WAIT:
+		/* system clock disabled, bus clock enabled */
+		val |= PSTOPO_PSTOP2 << BP_PMCTRL_PSTOPO;
+		break;
+	case ULP_PM_STOP:
+		/* system/bus clock disabled */
+		val |= PSTOPO_PSTOP1 << BP_PMCTRL_PSTOPO;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel_relaxed(val, smc1_base + SMC_PMCTRL);
+
+	return 0;
+}
 
 void __init imx7ulp_pm_init(void)
 {
 	struct device_node *np;
-	void __iomem *smc1_base;
 
 	np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-smc1");
 	smc1_base = of_iomap(np, 0);
 	WARN_ON(!smc1_base);
 
-	/* Partial Stop mode 3 with system/bus clock enabled */
-	writel_relaxed(PSTOPO_PSTOP3 << BP_PMCTRL_PSTOPO,
-		       smc1_base + SMC_PMCTRL);
-	iounmap(smc1_base);
+	imx7ulp_set_lpm(ULP_PM_RUN);
 }