Thread (15 messages) 15 messages, 2 authors, 2015-04-03

Re: [2/4] powerpc/rcpm: add RCPM driver

From: chenhui.zhao@freescale.com <hidden>
Date: 2015-04-02 10:33:30
Also in: linux-devicetree, lkml


________________________________________
From: Wood Scott-B07421
Sent: Tuesday, March 31, 2015 9:30
To: Zhao Chenhui-B35336
Cc: linuxppc-dev@lists.ozlabs.org; devicetree@vger.kernel.org; linux-kernel=
@vger.kernel.org; Jin Zhengxiong-R64188
Subject: Re: [2/4] powerpc/rcpm: add RCPM driver

On Thu, Mar 26, 2015 at 06:18:13PM +0800, chenhui zhao wrote:
There is a RCPM (Run Control/Power Management) in Freescale QorIQ
series processors. The device performs tasks associated with device
run control and power management.

The driver implements some features: mask/unmask irq, enter/exit low
power states, freeze time base, etc.

Signed-off-by: Chenhui Zhao <redacted>
---
 Documentation/devicetree/bindings/soc/fsl/rcpm.txt |  23 ++
 arch/powerpc/include/asm/fsl_guts.h                | 105 ++++++
 arch/powerpc/include/asm/fsl_pm.h                  |  49 +++
 arch/powerpc/platforms/85xx/Kconfig                |   1 +
 arch/powerpc/sysdev/Kconfig                        |   5 +
 arch/powerpc/sysdev/Makefile                       |   1 +
 arch/powerpc/sysdev/fsl_rcpm.c                     | 353 +++++++++++++++=
++++++
quoted hunk ↗ jump to hunk
 7 files changed, 537 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/rcpm.txt
 create mode 100644 arch/powerpc/include/asm/fsl_pm.h
 create mode 100644 arch/powerpc/sysdev/fsl_rcpm.c
diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documen=
tation/devicetree/bindings/soc/fsl/rcpm.txt
quoted hunk ↗ jump to hunk
new file mode 100644
index 0000000..8c21b6c
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt
@@ -0,0 +1,23 @@
+* Run Control and Power Management
+
+The RCPM performs all device-level tasks associated with device run cont=
rol
+and power management.
+
+Required properites:
+  - reg : Offset and length of the register set of RCPM block.
+  - compatible : Specifies the compatibility list for the RCPM. The type
+    should be string, such as "fsl,qoriq-rcpm-1.0", "fsl,qoriq-rcpm-2.0"=
.
+
+Example:
+The RCPM node for T4240:
+     rcpm: global-utilities@e2000 {
+             compatible =3D "fsl,t4240-rcpm", "fsl,qoriq-rcpm-2.0";
+             reg =3D <0xe2000 0x1000>;
+     };
+
+The RCPM node for P4080:
+     rcpm: global-utilities@e2000 {
+             compatible =3D "fsl,qoriq-rcpm-1.0";
+             reg =3D <0xe2000 0x1000>;
+             #sleep-cells =3D <1>;
+     };
Where is #sleep-cells documented?  It's copy-and-paste from something
that was never finished from many years ago.

[chenhui] Will get rid of them.
quoted hunk ↗ jump to hunk
diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm=
/fsl_pm.h
quoted hunk ↗ jump to hunk
new file mode 100644
index 0000000..bbe6089
--- /dev/null
+++ b/arch/powerpc/include/asm/fsl_pm.h
@@ -0,0 +1,49 @@
+/*
+ * Support Power Management
+ *
+ * Copyright 2014-2015 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify=
 it
+ * under  the terms of  the GNU General  Public License as published by =
the
+ * Free Software Foundation;  either version 2 of the  License, or (at y=
our
+ * option) any later version.
+ */
+#ifndef __PPC_FSL_PM_H
+#define __PPC_FSL_PM_H
+#ifdef       __KERNEL__
Put a space after #ifdef, not a tab.

[Chenhui] Will change it.
+#define E500_PM_PH10 1
+#define E500_PM_PH15 2
+#define E500_PM_PH20 3
+#define E500_PM_PH30 4
+#define E500_PM_DOZE E500_PM_PH10
+#define E500_PM_NAP  E500_PM_PH15
+
+#define PLAT_PM_SLEEP        20
+#define PLAT_PM_LPM20        30
+
+#define FSL_PM_SLEEP         (1 << 0)
+#define FSL_PM_DEEP_SLEEP    (1 << 1)
+
+struct fsl_pm_ops {
+     /* mask pending interrupts to the RCPM from MPIC */
+     void (*irq_mask)(int cpu);
+     /* unmask pending interrupts to the RCPM from MPIC */
+     void (*irq_unmask)(int cpu);
+     /* place the CPU in the specified state */
+     void (*cpu_enter_state)(int cpu, int state);
+     /* exit the CPU from the specified state */
+     void (*cpu_exit_state)(int cpu, int state);
+     /* place the platform in the sleep state */
+     int (*plat_enter_sleep)(void);
+     /* freeze the time base */
+     void (*freeze_time_base)(int freeze);
+     /* keep the power of IP blocks during sleep/deep sleep */
+     void (*set_ip_power)(int enable, u32 *mask);
+     /* get platform supported power management modes */
+     unsigned int (*get_pm_modes)(void);
+};
Drop the comments that are basically just a restatement of the function
name.  Where there are comments, it'd be easier to read with a blank line
between a function and the next comment.

s/int enable/bool enable/
s/int freeze/bool freeze/

[chenhui] Yes, you are right.
+#endif       /* __KERNEL__ */
+#endif  /* __PPC_FSL_PM_H */
Please be consistent with whitespace.
+     default:
+             pr_err("%s: Unknown cpu PM state (%d)\n", __func__, state);
WARN?
+static int rcpm_v2_plat_enter_state(int state)
+{
+     u32 *pmcsr_reg =3D &rcpm_v2_regs->powmgtcsr;
+     int ret =3D 0;
+     int result;
+
+     switch (state) {
+     case PLAT_PM_LPM20:
+             /* clear previous LPM20 status */
+             setbits32(pmcsr_reg, RCPM_POWMGTCSR_P_LPM20_ST);
How would the bit be set when you enter here, given that you wait for it
to clear when leaving?

[chenhui] Actually, the bit is not used by software. Just follow the instru=
ction in RM.
+             /* enter LPM20 status */
+             setbits32(pmcsr_reg, RCPM_POWMGTCSR_LPM20_RQ);
+
+             /* At this point, the device is in LPM20 status. */
+
+             /* resume ... */
+             result =3D spin_event_timeout(
+               !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_LPM20_ST), 10000, 1=
0);
+             if (!result) {
+                     pr_err("%s: timeout waiting for LPM20 bit to be cle=
ared\n",
+                            __func__);
+                     ret =3D -ETIMEDOUT;
+             }
+             break;
"At this point" is a bit misleading.  I think it's clear enough if you
just drop that comment.
+     default:
+             pr_err("%s: Unknown platform PM state (%d)\n",
+                    __func__, state);
+             ret =3D -EINVAL;
+     }
WARN?
+static const struct of_device_id rcpm_matches[] =3D {
+     {
+             .compatible =3D "fsl,qoriq-rcpm-1.0",
+             .data =3D (void *)RCPM_V1,
+     },
+     {
+             .compatible =3D "fsl,qoriq-rcpm-2.0",
+             .data =3D (void *)RCPM_V2,
+     },
Why not point .data directly at the ops?

[chenhui] I agree.
+     switch ((unsigned long)match->data) {
+     case RCPM_V1:
+             rcpm_v1_regs =3D base;
+             qoriq_pm_ops =3D &qoriq_rcpm_v1_ops;
+             break;
+
+     case RCPM_V2:
+             rcpm_v2_regs =3D base;
+             qoriq_pm_ops =3D &qoriq_rcpm_v2_ops;
+             break;
+
+     default:
+             break;
+     }
default: break; is unnecessary (and impossible to hit -- if you really
want default: it should probably WARN).

-Scott

[chenhui] Will get rid of them.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help