Skip to contentSkip to conversation

CPU Idle for Armada 370 and Armada 38x

PATCH New Gregory CLEMENT 4 participants 60 messages Jun 27, 2014 – Jul 3, 2014

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover CPU Idle for Armada 370 and Armada 38x

Hello,

This patch set adds the CPU Idle support for two mvebu SoCs: the Armada 370 and the Armada 38x. As there are common parts with the current support of cpuidle of the Armada XP. I made the code even more generic. Thanks to this change, adding a new SoC is now only done in the architecture specific part and we won't have to touch the cpuidle driver anymore for this.

The first patch is a preliminary clean-up.

The patches 2 and 3 allow to use a common function for the boot address work around.

The patches 4 and 5 use this function for SMP in the Armada 375 and CPU idle for the Armada 370.

The patches 6 to 9 and 12 to 13 make the cpu idle support more generic.

The patches 10 and 11 prepare the cpu idle support for the Armada 38x

The patches 14 and 15 are the ones which really add the cpuidle support for the Armada 370 and the Armada38x.

And finally the patch 16 updates mvebu_v7_defconfig by selecting the cpu idle support.

The patches 12 and 13 modify in the same time cpuidle driver and mvebu code. I need to do this in order to be bisectable. It seems to me that the easier would be to get the acked-by from the cpuidle maintainer for this two patches and merged them through the mvebu tree as all the other patches of the series should also go to the mvebu tree.

Thanks!

Gregory CLEMENT (16):
ARM: mvebu: Sort the headers of pmsu.c in alphabetic order
ARM: mvebu: Add a common function for the boot address work around
ARM: mvebu: Add function to export the physical address of the boot
register
ARM: mvebu: Use the common function for Armada 375 SMP workaround
ARM: mvebu: Add workaround for cpuidle support for Armada 370
ARM: mvebu: Rename the armada_370_xp into mvebu_v7 in pmsu.c file
ARM: mvebu: Make the CPU idle initialization more generic
ARM: mvebu: Use a local variable to store the resume address
ARM: mvebu: Make the snoop disable optional in
mvebu_v7_pmsu_idle_prepare
ARM: mvebu: Export the SCU address
ARM: mvebu: dts: Add CA9 MPcore SoC Controller node
cpuidle: mvebu: Rename the driver from armada-370-xp to mvebu-v7
cpuidle: mvebu: Move the description of the cpuidle states in the
platform part
ARM: mvebu: Add CPU idle support for Armada 370
ARM: mvebu: Add CPU idle support for Armada 38x
ARM: mvebu: defconfig: Enable CPU Idle support in mvebu_v7_defconfig

 .../bindings/arm/armada-380-mpcore-soc-ctrl.txt    |  14 +
 arch/arm/boot/dts/armada-38x.dtsi                  |   5 +
 arch/arm/configs/mvebu_v7_defconfig                |   2 +
 arch/arm/mach-mvebu/board-v7.c                     |   9 +-
 arch/arm/mach-mvebu/common.h                       |   3 +
 arch/arm/mach-mvebu/headsmp-a9.S                   |  11 -
 arch/arm/mach-mvebu/platsmp-a9.c                   |  27 +-
 arch/arm/mach-mvebu/pmsu.c                         | 312 ++++++++++++++++++---
 arch/arm/mach-mvebu/pmsu.h                         |   1 +
 arch/arm/mach-mvebu/pmsu_ll.S                      |  33 +++
 arch/arm/mach-mvebu/system-controller.c            |  11 +
 drivers/cpuidle/Kconfig.arm                        |   6 +-
 drivers/cpuidle/Makefile                           |   2 +-
 drivers/cpuidle/cpuidle-armada-370-xp.c            |  93 ------
 drivers/cpuidle/cpuidle-mvebu-v7.c                 |  76 +++++
 include/linux/mvebu-v7-cpuidle.h                   |  24 ++
 16 files changed, 456 insertions(+), 173 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt
 delete mode 100644 drivers/cpuidle/cpuidle-armada-370-xp.c
 create mode 100644 drivers/cpuidle/cpuidle-mvebu-v7.c
 create mode 100644 include/linux/mvebu-v7-cpuidle.h
Signature · 1 line
1.8.1.2
#1 lore raw

PATCH 1/16 ARM: mvebu: Sort the headers of pmsu.c in alphabetic order

Sorting the headers in alphabetic order will help to reduce the conflict when adding new headers later.

---
 arch/arm/mach-mvebu/pmsu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/arm/mach-mvebu/pmsu.c +3 -3
index a1d407c0febe..5584d35b8e88 100644
@@ -19,13 +19,13 @@
 #define pr_fmt(fmt) "mvebu-pmsu: " fmt
 
 #include <linux/cpu_pm.h>
-#include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/of_address.h>
+#include <linux/kernel.h>
 #include <linux/io.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
-#include <linux/smp.h>
 #include <linux/resource.h>
+#include <linux/smp.h>
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
 #include <asm/smp_plat.h>
Signature · 1 line
1.8.1.2
#2 lore raw

PATCH 1/16 ARM: mvebu: Sort the headers of pmsu.c in alphabetic order

Gregory,

Quoted 13 lines · Gregory CLEMENT

Sorting the headers in alphabetic order will help to reduce the conflict when adding new headers later.

---
 arch/arm/mach-mvebu/pmsu.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
arch/arm/mach-mvebu/pmsu.c +0 -0
index a1d407c0febe..5584d35b8e88 100644

arch/arm/mach-mvebu/pmsu.c line 24

Quoted 8 lines
arch/arm/mach-mvebu/pmsu.c +1 -2
@@ -19,13 +19,13 @@
 #define pr_fmt(fmt) "mvebu-pmsu: " fmt
 
 #include <linux/cpu_pm.h>
-#include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/of_address.h>
+#include <linux/kernel.h>
 #include <linux/io.h>

So, with your patch applied, if I'm correct, we will have:

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>

It seems like we're not yet alphabetically sorted here :)

Best regards,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#3 lore raw

PATCH 1/16 ARM: mvebu: Sort the headers of pmsu.c in alphabetic order

Hi Thomas,

Quoted 9 lines

arch/arm/mach-mvebu/pmsu.c line 24

Quoted 6 lines

#include <linux/cpu_pm.h>

arch/arm/mach-mvebu/pmsu.c +1 -2
-#include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/of_address.h>
+#include <linux/kernel.h>
 #include <linux/io.h>

So, with your patch applied, if I'm correct, we will have:

Quoted 5 lines

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>

It seems like we're not yet alphabetically sorted here :)

Indeed, I will fix it

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#4 lore raw

PATCH 2/16 ARM: mvebu: Add a common function for the boot address work around

In reply to Gregory CLEMENT

On some of the mvebu SoC and due to internal bootrom issue, CPU initial jump code should be placed in SRAM memory of the SoC. In order to achieve this, we have to unmap the BootROM and at some specific location where the BootROM was place, create a specific MBus window for the SRAM. This SRAM is initialized with a few instructions of code that allows to jump into the real secondary CPU boot address.

This work around currently needed for booting SMP on Aramda 375 Z1 and will be needed for cpuidle support on Armada 370. Instead of duplicate the same code, this commit introduce a common function to handle it:
mvebu_boot_addr_wa().

---
 arch/arm/mach-mvebu/pmsu.c    | 31 +++++++++++++++++++++++++++++++
 arch/arm/mach-mvebu/pmsu.h    |  1 +
 arch/arm/mach-mvebu/pmsu_ll.S | 19 +++++++++++++++++++
 3 files changed, 51 insertions(+)
arch/arm/mach-mvebu/pmsu.c +31 -0
index 5584d35b8e88..991560905ccc 100644
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
+#include <linux/mbus.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/resource.h>
@@ -63,6 +64,14 @@ static void __iomem *pmsu_mp_base;
 #define L2C_NFABRIC_PM_CTL		    0x4
 #define L2C_NFABRIC_PM_CTL_PWR_DOWN		BIT(20)
 
+#define ARMADA_370_CRYPT0_ENG_ID	0x9
+#define CRYPT0_ENG_ATTR	0x1
+
+#define SRAM_PHYS_BASE	    0xFFFF0000
+
+#define BOOTROM_BASE    0xFFF00000
+#define BOOTROM_SIZE    0x100000
+
 extern void ll_disable_coherency(void);
 extern void ll_enable_coherency(void);
 
@@ -85,6 +94,28 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
 		PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
 }
 
+extern unsigned char mvebu_boot_wa_start;
+extern unsigned char mvebu_boot_wa_end;
+
+void mvebu_boot_addr_wa(int crypto_eng_id, u32 resume_addr_reg)
+{
+	void __iomem *sram_virt_base;
+	u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start;
+
+	mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
+	mvebu_mbus_add_window_by_id(crypto_eng_id, CRYPT0_ENG_ATTR,
+				SRAM_PHYS_BASE, SZ_64K);
+	sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
+
+
+	memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len);
+	/*
+	 * The last word of the code copied in SRAM must contain the
+	 * physical base address of the PMSU register
+	 */
+	*(unsigned long *)(sram_virt_base + code_len - 4) = resume_addr_reg;
+}
+
 static int __init armada_370_xp_pmsu_init(void)
 {
 	struct device_node *np;
arch/arm/mach-mvebu/pmsu.h +1 -0
index 07a737c6b95d..2d97a70c2558 100644
@@ -12,5 +12,6 @@
 #define __MACH_MVEBU_PMSU_H
 
 int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
+void mvebu_boot_addr_wa(int crypto_eng_id, unsigned long resume_addr_reg);
 
 #endif	/* __MACH_370_XP_PMSU_H */
arch/arm/mach-mvebu/pmsu_ll.S +19 -0
index fc3de68d8c54..3b702a16bd3d 100644
@@ -23,3 +23,22 @@ ARM_BE8(setend	be )			@ go BE8 if entered LE
 	b	cpu_resume
 ENDPROC(armada_370_xp_cpu_resume)
 
+.global mvebu_boot_wa_start
+.global mvebu_boot_wa_end
+
+/* The following code will be executed from SRAM */
+ENTRY(mvebu_boot_wa_start)
+mvebu_boot_wa_start:
+/* use physical address of the boot address register register */
+	adr     r0, 1f
+	ldr     r0, [r0]
+	ldr     r0, [r0]
+	mov     pc, r0
+/*
+ * the last word of this piece of code will be filled by the physical
+ * address of the boot address register just after being copied in SRAM
+ */
+1:
+	.long   .
+mvebu_boot_wa_end:
+ENDPROC(mvebu_boot_wa_end)
Signature · 1 line
1.8.1.2
#5 lore raw

PATCH 2/16 ARM: mvebu: Add a common function for the boot address work around

Gregory,

Quoted 1 line · Gregory CLEMENT

On some of the mvebu SoC and due to internal bootrom issue, CPU

"due to an internal BootROM issue, the CPU"

Quoted 1 line

initial jump code should be placed in SRAM memory of the SoC. In order

"in SRAM memory" -> "in the SRAM memory".

Quoted 2 lines

to achieve this, we have to unmap the BootROM and at some specific location where the BootROM was place, create a specific MBus window

place -> placed

Quoted 2 lines

for the SRAM. This SRAM is initialized with a few instructions of code that allows to jump into the real secondary CPU boot address.

jump into -> jump to.

Quoted 1 line

This work around currently needed for booting SMP on Aramda 375 Z1 and

This work around *is* currently needed for SMP support on *Armada*.

Quoted 1 line

will be needed for cpuidle support on Armada 370. Instead of duplicate

duplicate -> duplicating.

Quoted 1 line

the same code, this commit introduce a common function to handle it:

introduce -> introduces.

Quoted 1 line

mvebu_boot_addr_wa().

I'm not sure the name of the function is appropriate, as we don't know what it is doing. Maybe mvebu_setup_boot_addr_wa() ?

Also, maybe your commit log should indicate that the workaround involves using the Crypto engine SRAM, which will help understanding the reference to the crypto engine in the code.

Quoted 6 lines
---
 arch/arm/mach-mvebu/pmsu.c    | 31 +++++++++++++++++++++++++++++++
 arch/arm/mach-mvebu/pmsu.h    |  1 +
 arch/arm/mach-mvebu/pmsu_ll.S | 19 +++++++++++++++++++
 3 files changed, 51 insertions(+)

I don't really have a better suggestion, but the workaround doesn't seem to be related to the PMSU, so are pmsu.c and pmsu_ll.S really the right files to store this code?

Quoted 14 lines
arch/arm/mach-mvebu/pmsu.c +1 -0
index 5584d35b8e88..991560905ccc 100644
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
+#include <linux/mbus.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/resource.h>

arch/arm/mach-mvebu/pmsu.c static void __iomem *pmsu_mp_base; · line 67

Quoted 4 lines
arch/arm/mach-mvebu/pmsu.c +1 -0
@@ -63,6 +64,14 @@ static void __iomem *pmsu_mp_base;
 #define L2C_NFABRIC_PM_CTL		    0x4
 #define L2C_NFABRIC_PM_CTL_PWR_DOWN		BIT(20)
 
+#define ARMADA_370_CRYPT0_ENG_ID	0x9

Not needed in this file, the MBus window target ID is passed as argument to the mvebu_boot_addr_wa() function.

arch/arm/mach-mvebu/pmsu.c static void __iomem *pmsu_mp_base; · line 68

Quoted 1 line
arch/arm/mach-mvebu/pmsu.c +1 -0
+#define CRYPT0_ENG_ATTR	0x1

For consistency, I'd prefer to see this being passed as argument to mvebu_boot_addr_wa().

Quoted 9 lines
arch/arm/mach-mvebu/pmsu.c +5 -0
+#define SRAM_PHYS_BASE	    0xFFFF0000
+
+#define BOOTROM_BASE    0xFFF00000
+#define BOOTROM_SIZE    0x100000
+
 extern void ll_disable_coherency(void);
 extern void ll_enable_coherency(void);
 

arch/arm/mach-mvebu/pmsu.c void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) · line 100

Quoted 7 lines
arch/arm/mach-mvebu/pmsu.c +4 -0
@@ -85,6 +94,28 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
 		PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
 }
 
+extern unsigned char mvebu_boot_wa_start;
+extern unsigned char mvebu_boot_wa_end;
+
+void mvebu_boot_addr_wa(int crypto_eng_id, u32 resume_addr_reg)

unsigned int crypto_eng_target ('unsigned int' is the type used by the mvebu-mbus API), and add unsigned int crypto_eng_attribute, to match the mvebu-mbus API. Also, void * seems more appropriate than u32 for an address, maybe even void __iomem * since it's actually pointing to a memory-mapped register.

arch/arm/mach-mvebu/pmsu.c void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) · line 108

Quoted 8 lines
arch/arm/mach-mvebu/pmsu.c +8 -0
+{
+	void __iomem *sram_virt_base;
+	u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start;
+
+	mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
+	mvebu_mbus_add_window_by_id(crypto_eng_id, CRYPT0_ENG_ATTR,
+				SRAM_PHYS_BASE, SZ_64K);
+	sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);

Maybe a return value check?

arch/arm/mach-mvebu/pmsu.c void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) · line 110

Quoted 2 lines
arch/arm/mach-mvebu/pmsu.c +2 -0
+
+

One too many new line.

arch/arm/mach-mvebu/pmsu.c void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) · line 116

Quoted 6 lines
arch/arm/mach-mvebu/pmsu.c +6 -0
+	memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len);
+	/*
+	 * The last word of the code copied in SRAM must contain the
+	 * physical base address of the PMSU register
+	 */
+	*(unsigned long *)(sram_virt_base + code_len - 4) = resume_addr_reg;

Maybe instead:

	writel(resume_addr_reg, sram_virt_base + code_len - 4);

And also:

	iounmap(sram_virt_base);
Quoted 21 lines
arch/arm/mach-mvebu/pmsu.c +2 -0
+}
+
 static int __init armada_370_xp_pmsu_init(void)
 {
 	struct device_node *np;
arch/arm/mach-mvebu/pmsu.h +1 -0
index 07a737c6b95d..2d97a70c2558 100644
@@ -12,5 +12,6 @@
 #define __MACH_MVEBU_PMSU_H
 
 int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
+void mvebu_boot_addr_wa(int crypto_eng_id, unsigned long resume_addr_reg);
 
 #endif	/* __MACH_370_XP_PMSU_H */
arch/arm/mach-mvebu/pmsu_ll.S +0 -0
index fc3de68d8c54..3b702a16bd3d 100644

arch/arm/mach-mvebu/pmsu_ll.S ARM_BE8(setend be ) @ go BE8 if entered LE · line 32

Quoted 10 lines
arch/arm/mach-mvebu/pmsu_ll.S +7 -0
@@ -23,3 +23,22 @@ ARM_BE8(setend	be )			@ go BE8 if entered LE
 	b	cpu_resume
 ENDPROC(armada_370_xp_cpu_resume)
 
+.global mvebu_boot_wa_start
+.global mvebu_boot_wa_end
+
+/* The following code will be executed from SRAM */
+ENTRY(mvebu_boot_wa_start)
+mvebu_boot_wa_start:
+/* use physical address of the boot address register register */

"register register" -> register.

arch/arm/mach-mvebu/pmsu_ll.S ARM_BE8(setend be ) @ go BE8 if entered LE · line 38

Quoted 6 lines
arch/arm/mach-mvebu/pmsu_ll.S +6 -0
+	adr     r0, 1f
+	ldr     r0, [r0]
+	ldr     r0, [r0]
+	mov     pc, r0
+/*
+ * the last word of this piece of code will be filled by the physical

"filled with". "filled by" indicates *who* is filling the missing information, "filled with" indicates with *what* it is being filled.

arch/arm/mach-mvebu/pmsu_ll.S ARM_BE8(setend be ) @ go BE8 if entered LE · line 44

Quoted 6 lines
arch/arm/mach-mvebu/pmsu_ll.S +6 -0
+ * address of the boot address register just after being copied in SRAM
+ */
+1:
+	.long   .
+mvebu_boot_wa_end:
+ENDPROC(mvebu_boot_wa_end)

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#6 lore raw

PATCH 2/16 ARM: mvebu: Add a common function for the boot address work around

Hi Thomas,

Quoted 5 lines
Quoted 2 lines

mvebu_boot_addr_wa().

I'm not sure the name of the function is appropriate, as we don't know what it is doing. Maybe mvebu_setup_boot_addr_wa() ?

I try to avoid too long name because then we have to do a lot of multiline code. However I agree that this name is better, I will use it

Quoted 5 lines

Also, maybe your commit log should indicate that the workaround involves using the Crypto engine SRAM, which will help understanding the reference to the crypto engine in the code.

OK

Quoted 28 lines
Quoted 6 lines
---
 arch/arm/mach-mvebu/pmsu.c    | 31 +++++++++++++++++++++++++++++++
 arch/arm/mach-mvebu/pmsu.h    |  1 +
 arch/arm/mach-mvebu/pmsu_ll.S | 19 +++++++++++++++++++
 3 files changed, 51 insertions(+)

I don't really have a better suggestion, but the workaround doesn't seem to be related to the PMSU, so are pmsu.c and pmsu_ll.S really the right files to store this code?

Quoted 17 lines
arch/arm/mach-mvebu/pmsu.c +1 -0
index 5584d35b8e88..991560905ccc 100644
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
+#include <linux/mbus.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/resource.h>
@@ -63,6 +64,14 @@ static void __iomem *pmsu_mp_base;
 #define L2C_NFABRIC_PM_CTL		    0x4
 #define L2C_NFABRIC_PM_CTL_PWR_DOWN		BIT(20)
 
Quoted 4 lines

arch/arm/mach-mvebu/pmsu.c static void __iomem *pmsu_mp_base; · line 67

Quoted 1 line
arch/arm/mach-mvebu/pmsu.c +1 -0
+#define ARMADA_370_CRYPT0_ENG_ID	0x9

Not needed in this file, the MBus window target ID is passed as argument to the mvebu_boot_addr_wa() function.

OK

Quoted 5 lines

arch/arm/mach-mvebu/pmsu.c static void __iomem *pmsu_mp_base; · line 68

Quoted 2 lines
arch/arm/mach-mvebu/pmsu.c +1 -0
+#define CRYPT0_ENG_ATTR	0x1

For consistency, I'd prefer to see this being passed as argument to mvebu_boot_addr_wa().

The attribute is the same, so why bother with it? If later we have a SoC where this attribute can be different then I agree to add this argument.

Quoted 13 lines
Quoted 13 lines
arch/arm/mach-mvebu/pmsu.c +5 -0
+#define SRAM_PHYS_BASE	    0xFFFF0000
+
+#define BOOTROM_BASE    0xFFF00000
+#define BOOTROM_SIZE    0x100000
+
 extern void ll_disable_coherency(void);
 extern void ll_enable_coherency(void);
 
@@ -85,6 +94,28 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
 		PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
 }
 
Quoted 10 lines

arch/arm/mach-mvebu/pmsu.c void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) · line 100

Quoted 4 lines
arch/arm/mach-mvebu/pmsu.c +4 -0
+extern unsigned char mvebu_boot_wa_start;
+extern unsigned char mvebu_boot_wa_end;
+
+void mvebu_boot_addr_wa(int crypto_eng_id, u32 resume_addr_reg)

unsigned int crypto_eng_target ('unsigned int' is the type used by the mvebu-mbus API), and add unsigned int crypto_eng_attribute, to match the mvebu-mbus API. Also, void * seems more appropriate than u32 for an address, maybe even void __iomem * since it's actually pointing to a memory-mapped register.

I was lazy for the resume_addr_reg and u32 was easier to use, but indeed void __iomem * is better. I also agree for the other, I didn't notice it was unsigned int instead of int.

Quoted 11 lines

arch/arm/mach-mvebu/pmsu.c void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) · line 108

Quoted 9 lines
arch/arm/mach-mvebu/pmsu.c +8 -0
+{
+	void __iomem *sram_virt_base;
+	u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start;
+
+	mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
+	mvebu_mbus_add_window_by_id(crypto_eng_id, CRYPT0_ENG_ATTR,
+				SRAM_PHYS_BASE, SZ_64K);
+	sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);

Maybe a return value check?

yes

Quoted 15 lines

arch/arm/mach-mvebu/pmsu.c void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) · line 110

Quoted 3 lines
arch/arm/mach-mvebu/pmsu.c +2 -0
+
+

One too many new line.

arch/arm/mach-mvebu/pmsu.c void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) · line 116

Quoted 6 lines
arch/arm/mach-mvebu/pmsu.c +6 -0
+	memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len);
+	/*
+	 * The last word of the code copied in SRAM must contain the
+	 * physical base address of the PMSU register
+	 */
+	*(unsigned long *)(sram_virt_base + code_len - 4) = resume_addr_reg;

Maybe instead:

Quoted 1 line
	writel(resume_addr_reg, sram_virt_base + code_len - 4);

Oh yes I forgot it was "iomaped"

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#7 lore raw

PATCH 2/16 ARM: mvebu: Add a common function for the boot address work around

Gregory,

Quoted 7 lines · Gregory CLEMENT
Quoted 4 lines
Quoted 1 line

+#define CRYPT0_ENG_ATTR 0x1

For consistency, I'd prefer to see this being passed as argument to mvebu_boot_addr_wa().

The attribute is the same, so why bother with it? If later we have a SoC where this attribute can be different then I agree to add this argument.

Simply for consistency. MBus windows are defined by their target and attribute values, so it makes sense to always pass both these values, even if for the existing cases the attribute is for now always 0x1.

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#8 lore raw

PATCH 2/16 ARM: mvebu: Add a common function for the boot address work around

In reply to Gregory CLEMENT

Dear Gregory CLEMENT,

Quoted 10 lines · Gregory CLEMENT
(quoted diff) +10 -0
+extern unsigned char mvebu_boot_wa_start;
+extern unsigned char mvebu_boot_wa_end;
+
+void mvebu_boot_addr_wa(int crypto_eng_id, u32 resume_addr_reg)
+{
+	void __iomem *sram_virt_base;
+	u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start;
+
+	mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
+	mvebu_mbus_add_window_by_id(crypto_eng_id, CRYPT0_ENG_ATTR,

Review

Quoted 10 lines
(quoted diff) +10 -0
+				SRAM_PHYS_BASE, SZ_64K);
+	sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
+
+
+	memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len);
+	/*
+	 * The last word of the code copied in SRAM must contain the
+	 * physical base address of the PMSU register
+	 */
+	*(unsigned long *)(sram_virt_base + code_len - 4) = resume_addr_reg;

Contrary to what I said, use __raw_writel() and not writel() here, to keep the native endianness of the system when writing the value:

arch/arm/mach-mvebu/pmsu.c +4 -2
index 9c56f8c..2b37e01 100644
@@ -135,9 +135,11 @@ void mvebu_boot_addr_wa(int crypto_eng_id, u32 resume_addr_reg)
        memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len);
        /*
         * The last word of the code copied in SRAM must contain the
-        * physical base address of the PMSU register
+        * physical base address of the PMSU register. We
+        * intentionally store this address in the native endianness
+        * of the system.
         */
-       *(unsigned long *)(sram_virt_base + code_len - 4) = resume_addr_reg;
+       __raw_writel(resume_addr_reg, sram_virt_base + code_len - 4);
 }
 
Quoted 9 lines

+.global mvebu_boot_wa_start
+.global mvebu_boot_wa_end

(quoted diff) +7 -0
+
+/* The following code will be executed from SRAM */
+ENTRY(mvebu_boot_wa_start)
+mvebu_boot_wa_start:
+/* use physical address of the boot address register register */
+	adr     r0, 1f
+	ldr     r0, [r0]

Review

Quoted 10 lines
(quoted diff) +10 -0
+	ldr     r0, [r0]
+	mov     pc, r0
+/*
+ * the last word of this piece of code will be filled by the physical
+ * address of the boot address register just after being copied in SRAM
+ */
+1:
+	.long   .
+mvebu_boot_wa_end:
+ENDPROC(mvebu_boot_wa_end)

And this needs to be changed a bit to work properly in a big-endian configuration:

arch/arm/mach-mvebu/pmsu_ll.S +7 -4
index 15b823d..2f8b021 100644
@@ -43,11 +43,14 @@ ENDPROC(armada_38x_cpu_resume)
 /* The following code will be executed from SRAM */
 ENTRY(mvebu_boot_wa_start)
 mvebu_boot_wa_start:
-/* use physical address of the boot address register register */
+ARM_BE8(setend be )                    @ go BE8 if entered LE
        adr     r0, 1f
-       ldr     r0, [r0]
-       ldr     r0, [r0]
-       mov     pc, r0
+       ldr     r0, [r0]                @ load the address of the
+                                       @ resume register
+       ldr     r0, [r0]                @ load the value in the
+                                       @ resume register
+ARM_BE8(rev    r0, r0)                 @ the value is stored LE
+       mov     pc, r0                  @ jump to this value
 

Note that the first ldr r0, [r0] does not need a rev r0, r0 because the value is stored in the native endianness of the system thanks to the __raw_writel() mentioned before. However, the second ldr r0, [r0] reads the value in the Resume Address register, which is written in little-endian by the writel() call in mvebu_pmsu_set_cpu_boot_addr().

Could you include this in your next iteration of the patches?

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#9 lore raw

PATCH 2/16 ARM: mvebu: Add a common function for the boot address work around

Hi Thomas,

Quoted 8 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+	/*
+	 * The last word of the code copied in SRAM must contain the
+	 * physical base address of the PMSU register
+	 */
+	*(unsigned long *)(sram_virt_base + code_len - 4) = resume_addr_reg;

Contrary to what I said, use __raw_writel() and not writel() here, to keep the native endianness of the system when writing the value:

Ok

[...]

Quoted 25 lines
arch/arm/mach-mvebu/pmsu_ll.S +7 -4
@@ -43,11 +43,14 @@ ENDPROC(armada_38x_cpu_resume)
 /* The following code will be executed from SRAM */
 ENTRY(mvebu_boot_wa_start)
 mvebu_boot_wa_start:
-/* use physical address of the boot address register register */
+ARM_BE8(setend be )                    @ go BE8 if entered LE
        adr     r0, 1f
-       ldr     r0, [r0]
-       ldr     r0, [r0]
-       mov     pc, r0
+       ldr     r0, [r0]                @ load the address of the
+                                       @ resume register
+       ldr     r0, [r0]                @ load the value in the
+                                       @ resume register
+ARM_BE8(rev    r0, r0)                 @ the value is stored LE
+       mov     pc, r0                  @ jump to this value
 

Note that the first ldr r0, [r0] does not need a rev r0, r0 because the value is stored in the native endianness of the system thanks to the __raw_writel() mentioned before. However, the second ldr r0, [r0] reads the value in the Resume Address register, which is written in little-endian by the writel() call in mvebu_pmsu_set_cpu_boot_addr().

Quoted 1 line

Could you include this in your next iteration of the patches?

Yes sure, and thanks again for having tested it in BE

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#10 lore raw

PATCH 3/16 ARM: mvebu: Add function to export the physical address of the boot register

In reply to Gregory CLEMENT

In order to boot the secondary CPUs on Armada 375 Z1, we need to read the boot address of these CPUs through a register part of the System Controller. This done very early where MMU is not enable yet, so we need to get the physical address of this register to use it.

In the previous version of this workaround the physical address were hardcoded whereas depending of the Mbus configuration this address may change.

This commit will allow to use the generic boot workaround function with the correct address.

---
 arch/arm/mach-mvebu/common.h            |  1 +
 arch/arm/mach-mvebu/system-controller.c | 11 +++++++++++
 2 files changed, 12 insertions(+)
arch/arm/mach-mvebu/common.h +1 -0
index b67fb7a10d8b..6ad62cf8352c 100644
@@ -20,6 +20,7 @@
 void mvebu_restart(enum reboot_mode mode, const char *cmd);
 int mvebu_cpu_reset_deassert(int cpu);
 void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr);
+u32 mvebu_system_controller_get_phys_addr(void);
 void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr);
 
 void armada_xp_cpu_die(unsigned int cpu);
arch/arm/mach-mvebu/system-controller.c +11 -0
index 0c5524ac75b7..ae6ab543aa36 100644
@@ -30,6 +30,7 @@
 #include "common.h"
 
 static void __iomem *system_controller_base;
+static u32 system_controller_phys_base;
 
 struct mvebu_system_controller {
 	u32 rstoutn_mask_offset;
@@ -109,6 +110,13 @@ void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
 	writel(virt_to_phys(boot_addr), system_controller_base +
 	       mvebu_sc->resume_boot_addr);
 }
+
+u32 mvebu_system_controller_get_phys_addr(void)
+{
+	BUG_ON(system_controller_phys_base == NULL);
+	BUG_ON(mvebu_sc->resume_boot_addr == 0);
+	return system_controller_phys_base + mvebu_sc->resume_boot_addr;
+}
 #endif
 
 static int __init mvebu_system_controller_init(void)
@@ -119,7 +127,10 @@ static int __init mvebu_system_controller_init(void)
 	np = of_find_matching_node_and_match(NULL, of_system_controller_table,
 					     &match);
 	if (np) {
+		struct resource res;
 		system_controller_base = of_iomap(np, 0);
+		of_address_to_resource(np, 0, &res);
+		system_controller_phys_base = res.start;
 		mvebu_sc = (struct mvebu_system_controller *)match->data;
 		of_node_put(np);
 	}
Signature · 1 line
1.8.1.2
#11 lore raw

PATCH 3/16 ARM: mvebu: Add function to export the physical address of the boot register

Quoted 11 lines · Gregory CLEMENT

In order to boot the secondary CPUs on Armada 375 Z1, we need to read the boot address of these CPUs through a register part of the System Controller. This done very early where MMU is not enable yet, so we need to get the physical address of this register to use it.

In the previous version of this workaround the physical address were hardcoded whereas depending of the Mbus configuration this address may change.

This commit will allow to use the generic boot workaround function with the correct address.

I forgot my signed-off here

Quoted 55 lines
---
 arch/arm/mach-mvebu/common.h            |  1 +
 arch/arm/mach-mvebu/system-controller.c | 11 +++++++++++
 2 files changed, 12 insertions(+)
arch/arm/mach-mvebu/common.h +1 -0
index b67fb7a10d8b..6ad62cf8352c 100644
@@ -20,6 +20,7 @@
 void mvebu_restart(enum reboot_mode mode, const char *cmd);
 int mvebu_cpu_reset_deassert(int cpu);
 void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr);
+u32 mvebu_system_controller_get_phys_addr(void);
 void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr);
 
 void armada_xp_cpu_die(unsigned int cpu);
arch/arm/mach-mvebu/system-controller.c +11 -0
index 0c5524ac75b7..ae6ab543aa36 100644
@@ -30,6 +30,7 @@
 #include "common.h"
 
 static void __iomem *system_controller_base;
+static u32 system_controller_phys_base;
 
 struct mvebu_system_controller {
 	u32 rstoutn_mask_offset;
@@ -109,6 +110,13 @@ void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
 	writel(virt_to_phys(boot_addr), system_controller_base +
 	       mvebu_sc->resume_boot_addr);
 }
+
+u32 mvebu_system_controller_get_phys_addr(void)
+{
+	BUG_ON(system_controller_phys_base == NULL);
+	BUG_ON(mvebu_sc->resume_boot_addr == 0);
+	return system_controller_phys_base + mvebu_sc->resume_boot_addr;
+}
 #endif
 
 static int __init mvebu_system_controller_init(void)
@@ -119,7 +127,10 @@ static int __init mvebu_system_controller_init(void)
 	np = of_find_matching_node_and_match(NULL, of_system_controller_table,
 					     &match);
 	if (np) {
+		struct resource res;
 		system_controller_base = of_iomap(np, 0);
+		of_address_to_resource(np, 0, &res);
+		system_controller_phys_base = res.start;
 		mvebu_sc = (struct mvebu_system_controller *)match->data;
 		of_node_put(np);
 	}
Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#12 lore raw

PATCH 3/16 ARM: mvebu: Add function to export the physical address of the boot register

In reply to Gregory CLEMENT

Gregory,

I'm not sure that the best approach to solve this problem. Instead, maybe the system-controller.c code should set up the boot address workaround on Armada 375. Since the workaround on 375 is really related to setting the boot address which is done by the system controller, maybe the initialization of the workaround belongs in system-controller.c ?

Quoted 4 lines · Gregory CLEMENT

In order to boot the secondary CPUs on Armada 375 Z1, we need to read the boot address of these CPUs through a register part of the System Controller. This done very early where MMU is not enable yet, so we need to get the physical address of this register to use it.

I don't think that really explains what's going on here, maybe:

"As part of a workaround for a BootROM issue on Armada 375 Z1, a piece of assembly code loaded into the Cryptographic Engine SRAM needs to read the System Controller Resume Address register before the MMU is enabled. We therefore need a way of getting the physical address for the System Controller Resume Address register."

Quoted 1 line

In the previous version of this workaround the physical address were

were -> was.

Quoted 38 lines

hardcoded whereas depending of the Mbus configuration this address may change.

This commit will allow to use the generic boot workaround function with the correct address.

---
 arch/arm/mach-mvebu/common.h            |  1 +
 arch/arm/mach-mvebu/system-controller.c | 11 +++++++++++
 2 files changed, 12 insertions(+)
arch/arm/mach-mvebu/common.h +1 -0
index b67fb7a10d8b..6ad62cf8352c 100644
@@ -20,6 +20,7 @@
 void mvebu_restart(enum reboot_mode mode, const char *cmd);
 int mvebu_cpu_reset_deassert(int cpu);
 void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr);
+u32 mvebu_system_controller_get_phys_addr(void);
 void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr);
 
 void armada_xp_cpu_die(unsigned int cpu);
arch/arm/mach-mvebu/system-controller.c +1 -0
index 0c5524ac75b7..ae6ab543aa36 100644
@@ -30,6 +30,7 @@
 #include "common.h"
 
 static void __iomem *system_controller_base;
+static u32 system_controller_phys_base;
 
 struct mvebu_system_controller {
 	u32 rstoutn_mask_offset;

arch/arm/mach-mvebu/system-controller.c void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) · line 114

Quoted 5 lines
arch/arm/mach-mvebu/system-controller.c +2 -0
@@ -109,6 +110,13 @@ void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
 	writel(virt_to_phys(boot_addr), system_controller_base +
 	       mvebu_sc->resume_boot_addr);
 }
+
+u32 mvebu_system_controller_get_phys_addr(void)

phys_addr_t should be the return type.

arch/arm/mach-mvebu/system-controller.c void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) · line 118

Quoted 4 lines
arch/arm/mach-mvebu/system-controller.c +4 -0
+{
+	BUG_ON(system_controller_phys_base == NULL);
+	BUG_ON(mvebu_sc->resume_boot_addr == 0);
+	return system_controller_phys_base + mvebu_sc->resume_boot_addr;

So the function name suggests you're returning the base physical address of the System Controller registers, while you're in fact returning the physical address of one particular register (the Resume Address one). I believe the function is misnamed.

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#13 lore raw

PATCH 3/16 ARM: mvebu: Add function to export the physical address of the boot register

Hi Thomas,

Quoted 8 lines · Thomas Petazzoni

Gregory,

I'm not sure that the best approach to solve this problem. Instead, maybe the system-controller.c code should set up the boot address workaround on Armada 375. Since the workaround on 375 is really related to setting the boot address which is done by the system controller, maybe the initialization of the workaround belongs in system-controller.c ?

So moving the workaround into mvebu_system_controller_set_cpu_boot_addr() should be the thing to do.

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#14 lore raw

PATCH 3/16 ARM: mvebu: Add function to export the physical address of the boot register

Dear Gregory CLEMENT,

Quoted 9 lines · Gregory CLEMENT
Quoted 6 lines

I'm not sure that the best approach to solve this problem. Instead, maybe the system-controller.c code should set up the boot address workaround on Armada 375. Since the workaround on 375 is really related to setting the boot address which is done by the system controller, maybe the initialization of the workaround belongs in system-controller.c ?

So moving the workaround into mvebu_system_controller_set_cpu_boot_addr() should be the thing to do.

Except that mvebu_system_controller_set_cpu_boot_addr() is called multiple times during the system execution, while you want the workaround to be initialized once. And we surely don't really want a static variable in there to test if the workaround has already been initialized or not.

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#15 lore raw

PATCH 3/16 ARM: mvebu: Add function to export the physical address of the boot register

Hi Thomas,

Quoted 11 lines · Thomas Petazzoni

Dear Gregory CLEMENT,

Quoted 7 lines · Gregory CLEMENT
Quoted 6 lines

I'm not sure that the best approach to solve this problem. Instead, maybe the system-controller.c code should set up the boot address workaround on Armada 375. Since the workaround on 375 is really related to setting the boot address which is done by the system controller, maybe the initialization of the workaround belongs in system-controller.c ?

Quoted 8 lines
Quoted 2 lines

So moving the workaround into mvebu_system_controller_set_cpu_boot_addr() should be the thing to do.

Except that mvebu_system_controller_set_cpu_boot_addr() is called multiple times during the system execution, while you want the workaround to be initialized once. And we surely don't really want a static variable in there to test if the workaround has already been initialized or not.

Actually mvebu_system_controller_set_cpu_boot_addr()? is called only in mvebu_cortex_a9_boot_secondary() just after the call to mvebu_boot_addr_wa().

So it won't change anything. Moreover the call to mvebu_cortex_a9_boot_secondary() is not expected to be done too often during the system execution.

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#16 lore raw

PATCH 3/16 ARM: mvebu: Add function to export the physical address of the boot register

In reply to Gregory CLEMENT

Dear Gregory CLEMENT,

arch/arm/mach-mvebu/system-controller.c void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) · line 116

Quoted 13 lines · Gregory CLEMENT

static void __iomem *system_controller_base;

arch/arm/mach-mvebu/system-controller.c +5 -0
+static u32 system_controller_phys_base;
 
 struct mvebu_system_controller {
 	u32 rstoutn_mask_offset;
@@ -109,6 +110,13 @@ void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
 	writel(virt_to_phys(boot_addr), system_controller_base +
 	       mvebu_sc->resume_boot_addr);
 }
+
+u32 mvebu_system_controller_get_phys_addr(void)
+{
+	BUG_ON(system_controller_phys_base == NULL);

This rightfully generates a fairly strong warning at compile time:
you're comparing an u32 to NULL. It should be == 0 here.

Best regards,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#17 lore raw

PATCH 3/16 ARM: mvebu: Add function to export the physical address of the boot register

Quoted 7 lines · Thomas Petazzoni

Dear Gregory CLEMENT,

Quoted 3 lines · Gregory CLEMENT

static void __iomem *system_controller_base;
+static u32 system_controller_phys_base;

Quoted 14 lines

arch/arm/mach-mvebu/system-controller.c void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) · line 116

Quoted 10 lines

struct mvebu_system_controller {

arch/arm/mach-mvebu/system-controller.c +4 -0
 	u32 rstoutn_mask_offset;
@@ -109,6 +110,13 @@ void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
 	writel(virt_to_phys(boot_addr), system_controller_base +
 	       mvebu_sc->resume_boot_addr);
 }
+
+u32 mvebu_system_controller_get_phys_addr(void)
+{
+	BUG_ON(system_controller_phys_base == NULL);

This rightfully generates a fairly strong warning at compile time:
you're comparing an u32 to NULL. It should be == 0 here.

Or a more readable BUG_ON(!system_controller_phys_base);

Signature · 3 lines
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
#18 lore raw

PATCH 4/16 ARM: mvebu: Use the common function for Armada 375 SMP workaround

In reply to Gregory CLEMENT

Use the common function mvebu_boot_addr_wa() introduced in the previous commit instead of the dedicated version for Armada 375.

In bonus we don't use anymore an harcoded value to access the register storing the boot address.

---
 arch/arm/mach-mvebu/headsmp-a9.S | 11 -----------
 arch/arm/mach-mvebu/platsmp-a9.c | 27 +++------------------------
 2 files changed, 3 insertions(+), 35 deletions(-)
arch/arm/mach-mvebu/headsmp-a9.S +0 -11
index 5925366bc03c..e48c8c495975 100644
@@ -16,17 +16,6 @@
 #include <linux/init.h>
 
 	__CPUINIT
-#define CPU_RESUME_ADDR_REG 0xf10182d4
-
-.global armada_375_smp_cpu1_enable_code_start
-.global armada_375_smp_cpu1_enable_code_end
-
-armada_375_smp_cpu1_enable_code_start:
-	ldr     r0, [pc, #4]
-	ldr     r1, [r0]
-	mov     pc, r1
-	.word   CPU_RESUME_ADDR_REG
-armada_375_smp_cpu1_enable_code_end:
 
 ENTRY(mvebu_cortex_a9_secondary_startup)
 	bl      v7_invalidate_l1
arch/arm/mach-mvebu/platsmp-a9.c +3 -24
index 96c2c59e34b6..5805c97502e3 100644
@@ -23,29 +23,7 @@
 #include "mvebu-soc-id.h"
 #include "pmsu.h"
 
-#define CRYPT0_ENG_ID   41
-#define CRYPT0_ENG_ATTR 0x1
-#define SRAM_PHYS_BASE  0xFFFF0000
-
-#define BOOTROM_BASE    0xFFF00000
-#define BOOTROM_SIZE    0x100000
-
-extern unsigned char armada_375_smp_cpu1_enable_code_end;
-extern unsigned char armada_375_smp_cpu1_enable_code_start;
-
-void armada_375_smp_cpu1_enable_wa(void)
-{
-	void __iomem *sram_virt_base;
-
-	mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
-	mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR,
-				SRAM_PHYS_BASE, SZ_64K);
-	sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
-
-	memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start,
-	       &armada_375_smp_cpu1_enable_code_end
-	       - &armada_375_smp_cpu1_enable_code_start);
-}
+#define ARMADA_375_CRYPT0_ENG_ID   41
 
 extern void mvebu_cortex_a9_secondary_startup(void);
 
@@ -69,7 +47,8 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
 
 		if (mvebu_get_soc_id(&dev, &rev) == 0 &&
 		    rev == ARMADA_375_Z1_REV)
-			armada_375_smp_cpu1_enable_wa();
+				mvebu_boot_addr_wa(ARMADA_375_CRYPT0_ENG_ID,
+					mvebu_system_controller_get_phys_addr());
 
 		mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
 	}
Signature · 1 line
1.8.1.2
#19 lore raw

PATCH 5/16 ARM: mvebu: Add workaround for cpuidle support for Armada 370

In reply to Gregory CLEMENT

On Armada 370, there is "a slow exit process from the deep idle state due to heavy L1/L2 cache cleanup operations performed by the BootROM software" (cf errata GL-BootROM-10). To avoid this, we replace the restart code of the BootROM by a simple jump to the boot address. Then the code located at this boot address will take care of the initialization.

For this purpose, we use the common function mvebu_boot_addr_wa() introduced in the previous commit.

---
 arch/arm/mach-mvebu/pmsu.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
arch/arm/mach-mvebu/pmsu.c +17 -1
index 991560905ccc..cdc6d87d0b49 100644
@@ -34,7 +34,6 @@
 #include <asm/tlbflush.h>
 #include "common.h"
 
-static void __iomem *pmsu_mp_base;
 
 #define PMSU_BASE_OFFSET    0x100
 #define PMSU_REG_SIZE	    0x1000
@@ -77,6 +76,9 @@ extern void ll_enable_coherency(void);
 
 extern void armada_370_xp_cpu_resume(void);
 
+static unsigned long pmsu_mp_phys_base;
+static void __iomem *pmsu_mp_base;
+
 static struct platform_device armada_xp_cpuidle_device = {
 	.name = "cpuidle-armada-370-xp",
 };
@@ -147,6 +149,8 @@ static int __init armada_370_xp_pmsu_init(void)
 		goto out;
 	}
 
+	pmsu_mp_phys_base = res.start;
+
 	pmsu_mp_base = ioremap(res.start, resource_size(&res));
 	if (!pmsu_mp_base) {
 		pr_err("unable to map registers\n");
@@ -312,6 +316,18 @@ int __init armada_370_xp_cpu_pm_init(void)
 		return 0;
 	of_node_put(np);
 
+	/*
+	 * On Armada 370, there is "a slow exit process from the deep
+	 * idle state due to heavy L1/L2 cache cleanup operations
+	 * performed by the BootROM software". To avoid this, we
+	 * replace the restart code of the bootrom by a a simple jump
+	 * to the boot address. Then the code located at this boot
+	 * address will take care of the initialization.
+	 */
+	if (of_machine_is_compatible("marvell,armada370"))
+		mvebu_boot_addr_wa(ARMADA_370_CRYPT0_ENG_ID, pmsu_mp_phys_base +
+				PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));
+
 	armada_370_xp_pmsu_enable_l2_powerdown_onidle();
 	armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
 	platform_device_register(&armada_xp_cpuidle_device);
Signature · 1 line
1.8.1.2
#20 lore raw

PATCH 5/16 ARM: mvebu: Add workaround for cpuidle support for Armada 370

Dear Gregory CLEMENT,

Quoted 9 lines · Gregory CLEMENT

On Armada 370, there is "a slow exit process from the deep idle state due to heavy L1/L2 cache cleanup operations performed by the BootROM software" (cf errata GL-BootROM-10). To avoid this, we replace the restart code of the BootROM by a simple jump to the boot address. Then the code located at this boot address will take care of the initialization.

For this purpose, we use the common function mvebu_boot_addr_wa() introduced in the previous commit.

"in the previous commit" would make sense if the commit immediately before this one in the series was the one you would be referencing. But that's not the case here, so it should be either: "introduced in one of the previous commits", or better "introduced in commit <title of the commit>".

arch/arm/mach-mvebu/pmsu.c extern void ll_enable_coherency(void); · line 79

Quoted 7 lines

#define PMSU_BASE_OFFSET 0x100
#define PMSU_REG_SIZE 0x1000

arch/arm/mach-mvebu/pmsu.c +1 -0
@@ -77,6 +76,9 @@ extern void ll_enable_coherency(void);
 
 extern void armada_370_xp_cpu_resume(void);
 
+static unsigned long pmsu_mp_phys_base;

phys_addr_t.

Quoted 23 lines
arch/arm/mach-mvebu/pmsu.c +9 -0
+static void __iomem *pmsu_mp_base;
+
 static struct platform_device armada_xp_cpuidle_device = {
 	.name = "cpuidle-armada-370-xp",
 };
@@ -147,6 +149,8 @@ static int __init armada_370_xp_pmsu_init(void)
 		goto out;
 	}
 
+	pmsu_mp_phys_base = res.start;
+
 	pmsu_mp_base = ioremap(res.start, resource_size(&res));
 	if (!pmsu_mp_base) {
 		pr_err("unable to map registers\n");
@@ -312,6 +316,18 @@ int __init armada_370_xp_cpu_pm_init(void)
 		return 0;
 	of_node_put(np);
 
+	/*
+	 * On Armada 370, there is "a slow exit process from the deep
+	 * idle state due to heavy L1/L2 cache cleanup operations
+	 * performed by the BootROM software". To avoid this, we
+	 * replace the restart code of the bootrom by a a simple jump

arch/arm/mach-mvebu/pmsu.c int __init armada_370_xp_cpu_pm_init(void) · line 333

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +7 -0
+	 * to the boot address. Then the code located at this boot
+	 * address will take care of the initialization.
+	 */
+	if (of_machine_is_compatible("marvell,armada370"))
+		mvebu_boot_addr_wa(ARMADA_370_CRYPT0_ENG_ID, pmsu_mp_phys_base +
+				PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));
+
 	armada_370_xp_pmsu_enable_l2_powerdown_onidle();
 	armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
 	platform_device_register(&armada_xp_cpuidle_device);

Other than that, looks good to me.

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#21 lore raw

PATCH 5/16 ARM: mvebu: Add workaround for cpuidle support for Armada 370

Hi Thomas,

Quoted 10 lines · Thomas Petazzoni

Dear Gregory CLEMENT,

Quoted 7 lines · Gregory CLEMENT

On Armada 370, there is "a slow exit process from the deep idle state due to heavy L1/L2 cache cleanup operations performed by the BootROM software" (cf errata GL-BootROM-10). To avoid this, we replace the restart code of the BootROM by a simple jump to the boot address. Then the code located at this boot address will take care of the initialization.

Quoted 8 lines
Quoted 2 lines

For this purpose, we use the common function mvebu_boot_addr_wa() introduced in the previous commit.

"in the previous commit" would make sense if the commit immediately before this one in the series was the one you would be referencing. But that's not the case here, so it should be either: "introduced in one of the previous commits", or better "introduced in commit <title of the commit>".

Yes it should have been the previous commit at a point of development and it was moved during a rebase. Using the title of the commit is more reliable indeed.

Quoted 10 lines

arch/arm/mach-mvebu/pmsu.c extern void ll_enable_coherency(void); · line 79

Quoted 8 lines

#define PMSU_BASE_OFFSET 0x100
#define PMSU_REG_SIZE 0x1000

arch/arm/mach-mvebu/pmsu.c +1 -0
@@ -77,6 +76,9 @@ extern void ll_enable_coherency(void);
 
 extern void armada_370_xp_cpu_resume(void);
 
+static unsigned long pmsu_mp_phys_base;

phys_addr_t.

OK

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#22 lore raw

PATCH 6/16 ARM: mvebu: Rename the armada_370_xp into mvebu_v7 in pmsu.c file

In reply to Gregory CLEMENT

Actually most of the function related to the PMSU are not specific to the Armada 370 or Armada XP SoCs, but can also be used for most of the other mvebu ARMv7 SoCs.

---
 arch/arm/mach-mvebu/pmsu.c | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)
arch/arm/mach-mvebu/pmsu.c +20 -20
index cdc6d87d0b49..087157c20b8a 100644
@@ -79,7 +79,7 @@ extern void armada_370_xp_cpu_resume(void);
 static unsigned long pmsu_mp_phys_base;
 static void __iomem *pmsu_mp_base;
 
-static struct platform_device armada_xp_cpuidle_device = {
+static struct platform_device mvebu_v7_cpuidle_device = {
 	.name = "cpuidle-armada-370-xp",
 };
 
@@ -118,7 +118,7 @@ void mvebu_boot_addr_wa(int crypto_eng_id, u32 resume_addr_reg)
 	*(unsigned long *)(sram_virt_base + code_len - 4) = resume_addr_reg;
 }
 
-static int __init armada_370_xp_pmsu_init(void)
+static int __init mvebu_v7_pmsu_init(void)
 {
 	struct device_node *np;
 	struct resource res;
@@ -164,7 +164,7 @@ static int __init armada_370_xp_pmsu_init(void)
 	return ret;
 }
 
-static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void)
+static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void)
 {
 	u32 reg;
 
@@ -178,7 +178,7 @@ static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void)
 }
 
 /* No locking is needed because we only access per-CPU registers */
-void armada_370_xp_pmsu_idle_prepare(bool deepidle)
+static void mvebu_v7_pmsu_idle_prepare(bool deepidle)
 {
 	unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
 	u32 reg;
@@ -215,9 +215,9 @@ void armada_370_xp_pmsu_idle_prepare(bool deepidle)
 	writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
 }
 
-static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle)
+static noinline int do_armada_xp_370_cpu_suspend(unsigned long deepidle)
 {
-	armada_370_xp_pmsu_idle_prepare(deepidle);
+	mvebu_v7_pmsu_idle_prepare(deepidle);
 
 	v7_exit_coherency_flush(all);
 
@@ -248,13 +248,13 @@ static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle)
 	return 0;
 }
 
-static int armada_370_xp_cpu_suspend(unsigned long deepidle)
+static int armada_xp_370_cpu_suspend(unsigned long deepidle)
 {
-	return cpu_suspend(deepidle, do_armada_370_xp_cpu_suspend);
+	return cpu_suspend(deepidle, do_armada_xp_370_cpu_suspend);
 }
 
 /* No locking is needed because we only access per-CPU registers */
-static noinline void armada_370_xp_pmsu_idle_restore(void)
+static noinline void mvebu_v7_pmsu_idle_restore(void)
 {
 	unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
 	u32 reg;
@@ -276,24 +276,24 @@ static noinline void armada_370_xp_pmsu_idle_restore(void)
 	writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
 }
 
-static int armada_370_xp_cpu_pm_notify(struct notifier_block *self,
+static int mvebu_v7_cpu_pm_notify(struct notifier_block *self,
 				    unsigned long action, void *hcpu)
 {
 	if (action == CPU_PM_ENTER) {
 		unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
 		mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume);
 	} else if (action == CPU_PM_EXIT) {
-		armada_370_xp_pmsu_idle_restore();
+		mvebu_v7_pmsu_idle_restore();
 	}
 
 	return NOTIFY_OK;
 }
 
-static struct notifier_block armada_370_xp_cpu_pm_notifier = {
-	.notifier_call = armada_370_xp_cpu_pm_notify,
+static struct notifier_block mvebu_v7_cpu_pm_notifier = {
+	.notifier_call = mvebu_v7_cpu_pm_notify,
 };
 
-int __init armada_370_xp_cpu_pm_init(void)
+static int __init mvebu_v7_cpu_pm_init(void)
 {
 	struct device_node *np;
 
@@ -328,13 +328,13 @@ int __init armada_370_xp_cpu_pm_init(void)
 		mvebu_boot_addr_wa(ARMADA_370_CRYPT0_ENG_ID, pmsu_mp_phys_base +
 				PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));
 
-	armada_370_xp_pmsu_enable_l2_powerdown_onidle();
-	armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
-	platform_device_register(&armada_xp_cpuidle_device);
-	cpu_pm_register_notifier(&armada_370_xp_cpu_pm_notifier);
+	mvebu_v7_pmsu_enable_l2_powerdown_onidle();
+	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
+	platform_device_register(&mvebu_v7_cpuidle_device);
+	cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier);
 
 	return 0;
 }
 
-arch_initcall(armada_370_xp_cpu_pm_init);
-early_initcall(armada_370_xp_pmsu_init);
+arch_initcall(mvebu_v7_cpu_pm_init);
+early_initcall(mvebu_v7_pmsu_init);
Signature · 1 line
1.8.1.2
#23 lore raw

PATCH 6/16 ARM: mvebu: Rename the armada_370_xp into mvebu_v7 in pmsu.c file

Dear Gregory CLEMENT,

Quoted 8 lines · Gregory CLEMENT

Actually most of the function related to the PMSU are not specific to the Armada 370 or Armada XP SoCs, but can also be used for most of the other mvebu ARMv7 SoCs.

---
 arch/arm/mach-mvebu/pmsu.c | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

I'm fine on the principle, but this badly conflicts with the PMSU changes I've made to support CPU hotplug, which are already in linux-next. See
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/log/arch/arm/mach-mvebu/pmsu.c.

arch/arm/mach-mvebu/pmsu.c static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) · line 181

Quoted 3 lines

/* No locking is needed because we only access per-CPU registers */

arch/arm/mach-mvebu/pmsu.c +1 -1
-void armada_370_xp_pmsu_idle_prepare(bool deepidle)
+static void mvebu_v7_pmsu_idle_prepare(bool deepidle)

Also, note here that you're not only renaming, but also adding the 'static' qualifier. This is already done in linux-next by
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/arch/arm/mach-mvebu/pmsu.c?id=adb1d99384c7480886153a97d2ea22e9c0d2e053,
but the function is anyway renamed in
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/arch/arm/mach-mvebu/pmsu.c?id=bbb92284b6c821e9434223d437fbd10b8a24c294
as a preparation for CPU hotplug support.

arch/arm/mach-mvebu/pmsu.c void armada_370_xp_pmsu_idle_prepare(bool deepidle) · line 218

Quoted 2 lines
arch/arm/mach-mvebu/pmsu.c +1 -1
-static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle)
+static noinline int do_armada_xp_370_cpu_suspend(unsigned long deepidle)

This does not seem like a rename to mvebu_v7.

arch/arm/mach-mvebu/pmsu.c static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle) · line 251

Quoted 12 lines

{

arch/arm/mach-mvebu/pmsu.c +2 -2
-	armada_370_xp_pmsu_idle_prepare(deepidle);
+	mvebu_v7_pmsu_idle_prepare(deepidle);
 
 	v7_exit_coherency_flush(all);
@@ -248,13 +248,13 @@ static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle)
 	return 0;
 }
 
-static int armada_370_xp_cpu_suspend(unsigned long deepidle)
+static int armada_xp_370_cpu_suspend(unsigned long deepidle)

Ditto.

arch/arm/mach-mvebu/pmsu.c static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle) · line 253

Quoted 3 lines
arch/arm/mach-mvebu/pmsu.c +1 -1
 {
-	return cpu_suspend(deepidle, do_armada_370_xp_cpu_suspend);
+	return cpu_suspend(deepidle, do_armada_xp_370_cpu_suspend);

Ditto.

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#24 lore raw

PATCH 6/16 ARM: mvebu: Rename the armada_370_xp into mvebu_v7 in pmsu.c file

Quoted 17 lines · Thomas Petazzoni

Dear Gregory CLEMENT,

Quoted 8 lines · Gregory CLEMENT

Actually most of the function related to the PMSU are not specific to the Armada 370 or Armada XP SoCs, but can also be used for most of the other mvebu ARMv7 SoCs.

---
 arch/arm/mach-mvebu/pmsu.c | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

I'm fine on the principle, but this badly conflicts with the PMSU changes I've made to support CPU hotplug, which are already in linux-next. See
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/log/arch/arm/mach-mvebu/pmsu.c.

Quoted 10 lines

arch/arm/mach-mvebu/pmsu.c static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) · line 181

Quoted 3 lines

/* No locking is needed because we only access per-CPU registers */

arch/arm/mach-mvebu/pmsu.c +1 -1
-void armada_370_xp_pmsu_idle_prepare(bool deepidle)
+static void mvebu_v7_pmsu_idle_prepare(bool deepidle)

Also, note here that you're not only renaming, but also adding the 'static' qualifier. This is already done in linux-next by
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/arch/arm/mach-mvebu/pmsu.c?id=adb1d99384c7480886153a97d2ea22e9c0d2e053,
but the function is anyway renamed in
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/arch/arm/mach-mvebu/pmsu.c?id=bbb92284b6c821e9434223d437fbd10b8a24c294
as a preparation for CPU hotplug support.

I am rebasing this series onto mvebu/fixes and mvebu/soc. I take care of all your remark during this rebasing.

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#25 lore raw

PATCH 7/16 ARM: mvebu: Make the CPU idle initialization more generic

In reply to Gregory CLEMENT

In order to support more mvebu SoCs, this patch use an initialization specific function associated to each SoCs which support CPU Idle.

Then each SoC will have his own set of check and of data configuration.

---
 arch/arm/mach-mvebu/pmsu.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)
arch/arm/mach-mvebu/pmsu.c +31 -8
index 087157c20b8a..454f0f9ede6b 100644
@@ -293,23 +293,47 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = {
 	.notifier_call = mvebu_v7_cpu_pm_notify,
 };
 
+static bool (*mvebu_v7_cpu_idle_init)(void);
+
+static __init bool armada_xp_cpuidle_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+	if (!np)
+		return false;
+	of_node_put(np);
+
+	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
+	return true;
+}
+
+static struct of_device_id of_cpuidle_table[] __initdata = {
+	{ .compatible = "marvell,armadaxp",
+	  .data = (void *)armada_xp_cpuidle_init,
+	},
+	{ /* end of list */ },
+};
+
 static int __init mvebu_v7_cpu_pm_init(void)
 {
 	struct device_node *np;
+	const struct of_device_id *match;
+
+	np = of_find_matching_node_and_match(NULL, of_cpuidle_table,
+					&match);
+
 
 	/*
 	 * Check that all the requirements are available to enable
-	 * cpuidle. So far, it is only supported on Armada XP, cpuidle
-	 * needs the coherency fabric and the PMSU enabled
+	 * cpuidle. Each SoCs comes with its own requirements and
+	 * configuration
 	 */
 
-	if (!of_machine_is_compatible("marvell,armadaxp"))
-		return 0;
+	mvebu_v7_cpu_idle_init = (bool (*)(void))match->data;
 
-	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
-	if (!np)
+	if (!mvebu_v7_cpu_idle_init())
 		return 0;
-	of_node_put(np);
 
 	np = of_find_matching_node(NULL, of_pmsu_table);
 	if (!np)
@@ -329,7 +353,6 @@ static int __init mvebu_v7_cpu_pm_init(void)
 				PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));
 
 	mvebu_v7_pmsu_enable_l2_powerdown_onidle();
-	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
 	platform_device_register(&mvebu_v7_cpuidle_device);
 	cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier);
 
Signature · 1 line
1.8.1.2
#26 lore raw

PATCH 7/16 ARM: mvebu: Make the CPU idle initialization more generic

Quoted 39 lines · Gregory CLEMENT

In order to support more mvebu SoCs, this patch use an initialization specific function associated to each SoCs which support CPU Idle.

Then each SoC will have his own set of check and of data configuration.

---
 arch/arm/mach-mvebu/pmsu.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)
arch/arm/mach-mvebu/pmsu.c +20 -0
index 087157c20b8a..454f0f9ede6b 100644
@@ -293,23 +293,47 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = {
 	.notifier_call = mvebu_v7_cpu_pm_notify,
 };
 
+static bool (*mvebu_v7_cpu_idle_init)(void);
+
+static __init bool armada_xp_cpuidle_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+	if (!np)
+		return false;
+	of_node_put(np);
+
+	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
+	return true;
+}
+
+static struct of_device_id of_cpuidle_table[] __initdata = {
+	{ .compatible = "marvell,armadaxp",
+	  .data = (void *)armada_xp_cpuidle_init,
+	},
+	{ /* end of list */ },

arch/arm/mach-mvebu/pmsu.c static struct notifier_block mvebu_v7_cpu_pm_notifier = { · line 325

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +7 -0
+};
+
 static int __init mvebu_v7_cpu_pm_init(void)
 {
 	struct device_node *np;
+	const struct of_device_id *match;
+
+	np = of_find_matching_node_and_match(NULL, of_cpuidle_table,
+					&match);
+

The following part was missing (without this the kernel hang on Armada 375)

+ if (!np)
+ return 0;

Quoted 30 lines
arch/arm/mach-mvebu/pmsu.c +4 -8
 	/*
 	 * Check that all the requirements are available to enable
-	 * cpuidle. So far, it is only supported on Armada XP, cpuidle
-	 * needs the coherency fabric and the PMSU enabled
+	 * cpuidle. Each SoCs comes with its own requirements and
+	 * configuration
 	 */
 
-	if (!of_machine_is_compatible("marvell,armadaxp"))
-		return 0;
+	mvebu_v7_cpu_idle_init = (bool (*)(void))match->data;
 
-	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
-	if (!np)
+	if (!mvebu_v7_cpu_idle_init())
 		return 0;
-	of_node_put(np);
 
 	np = of_find_matching_node(NULL, of_pmsu_table);
 	if (!np)
@@ -329,7 +353,6 @@ static int __init mvebu_v7_cpu_pm_init(void)
 				PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));
 
 	mvebu_v7_pmsu_enable_l2_powerdown_onidle();
-	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
 	platform_device_register(&mvebu_v7_cpuidle_device);
 	cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier);
 
Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#27 lore raw

PATCH 7/16 ARM: mvebu: Make the CPU idle initialization more generic

Gregory,

Quoted 53 lines · Gregory CLEMENT
Quoted 39 lines · Gregory CLEMENT

In order to support more mvebu SoCs, this patch use an initialization specific function associated to each SoCs which support CPU Idle.

Then each SoC will have his own set of check and of data configuration.

---
 arch/arm/mach-mvebu/pmsu.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)
arch/arm/mach-mvebu/pmsu.c +20 -0
index 087157c20b8a..454f0f9ede6b 100644
@@ -293,23 +293,47 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = {
 	.notifier_call = mvebu_v7_cpu_pm_notify,
 };
 
+static bool (*mvebu_v7_cpu_idle_init)(void);
+
+static __init bool armada_xp_cpuidle_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+	if (!np)
+		return false;
+	of_node_put(np);
+
+	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
+	return true;
+}
+
+static struct of_device_id of_cpuidle_table[] __initdata = {
+	{ .compatible = "marvell,armadaxp",
+	  .data = (void *)armada_xp_cpuidle_init,
+	},
+	{ /* end of list */ },

arch/arm/mach-mvebu/pmsu.c static struct notifier_block mvebu_v7_cpu_pm_notifier = { · line 325

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +7 -0
+};
+
 static int __init mvebu_v7_cpu_pm_init(void)
 {
 	struct device_node *np;
+	const struct of_device_id *match;
+
+	np = of_find_matching_node_and_match(NULL, of_cpuidle_table,
+					&match);
+

The following part was missing (without this the kernel hang on Armada 375)

Review

Quoted 2 lines
(quoted diff) +2 -0
+       if (!np)
+               return 0;

If there's no other changes, I can fix this up when I apply it. As well as the S-o-b.

thx,

Jason.

#28 lore raw

PATCH 7/16 ARM: mvebu: Make the CPU idle initialization more generic

Hi Jason,

Quoted 11 lines

Review

Quoted 8 lines

arch/arm/mach-mvebu/pmsu.c static struct notifier_block mvebu_v7_cpu_pm_notifier = { · line 325

Quoted 3 lines
arch/arm/mach-mvebu/pmsu.c +3 -0
+	np = of_find_matching_node_and_match(NULL, of_cpuidle_table,
+					&match);
+

The following part was missing (without this the kernel hang on Armada 375)

(quoted diff) +2 -0
+       if (!np)
+               return 0;

If there's no other changes, I can fix this up when I apply it. As well as the S-o-b.

Thanks. Let's hope it will be the case, and there will no need to a new version of this series. :)

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#29 lore raw

PATCH 7/16 ARM: mvebu: Make the CPU idle initialization more generic

In reply to Gregory CLEMENT

Gregory,

Quoted 19 lines · Gregory CLEMENT
arch/arm/mach-mvebu/pmsu.c +19 -0
+static bool (*mvebu_v7_cpu_idle_init)(void);
+
+static __init bool armada_xp_cpuidle_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+	if (!np)
+		return false;
+	of_node_put(np);
+
+	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
+	return true;
+}
+
+static struct of_device_id of_cpuidle_table[] __initdata = {
+	{ .compatible = "marvell,armadaxp",
+	  .data = (void *)armada_xp_cpuidle_init,
+	},

arch/arm/mach-mvebu/pmsu.c static struct notifier_block mvebu_v7_cpu_pm_notifier = { · line 324

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +7 -0
+	{ /* end of list */ },
+};
+
 static int __init mvebu_v7_cpu_pm_init(void)
 {
 	struct device_node *np;
+	const struct of_device_id *match;
+
+	np = of_find_matching_node_and_match(NULL, of_cpuidle_table,
+					&match);

I'm not sure I like using of_find_matching_node_and_match() on the entire tree to find the root node compatible string. Wouldn't it be simpler and shorter to just do:

	if (of_machine_is_compatible("marvell,armadaxp"))
		ret = armadaxp_cpuidle_init();
	else if (of_machine_is_compatible("marvell,armada370"))
		ret = armada370_cpuidle_init();
	else if (of_machine_is_compaitble("marvell,armada380"))
		ret = armada38x_cpuidle_init();

	if (ret)
		return ret;

Also, using a boolean to return a success/error status is not the kernel way of doing things, you should use an int instead and use proper error codes or return 0 on success.

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#30 lore raw

PATCH 7/16 ARM: mvebu: Make the CPU idle initialization more generic

Hi Thomas,

	struct device_node *np;
Quoted 9 lines

arch/arm/mach-mvebu/pmsu.c static struct notifier_block mvebu_v7_cpu_pm_notifier = { · line 324

Quoted 4 lines
arch/arm/mach-mvebu/pmsu.c +4 -0
+	const struct of_device_id *match;
+
+	np = of_find_matching_node_and_match(NULL, of_cpuidle_table,
+					&match);

I'm not sure I like using of_find_matching_node_and_match() on the entire tree to find the root node compatible string. Wouldn't it be simpler and shorter to just do:

Quoted 9 lines
	if (of_machine_is_compatible("marvell,armadaxp"))
		ret = armadaxp_cpuidle_init();
	else if (of_machine_is_compatible("marvell,armada370"))
		ret = armada370_cpuidle_init();
	else if (of_machine_is_compaitble("marvell,armada380"))
		ret = armada38x_cpuidle_init();

	if (ret)
		return ret;

Indeed, as I don't use any resource from the device tree here, using of_find_matching_node_and_match is overkill. And your alternative will be enough.

Quoted 4 lines

Also, using a boolean to return a success/error status is not the kernel way of doing things, you should use an int instead and use proper error codes or return 0 on success.

OK

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#31 lore raw

PATCH 8/16 ARM: mvebu: Use a local variable to store the resume address

In reply to Gregory CLEMENT

The resume address used by the cpu idle code will not always be the same. Using a local variable to store the resume address allows to keep the same function for the pm notifier but with a different address. This address will be set during the initialization.

---
 arch/arm/mach-mvebu/pmsu.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
arch/arm/mach-mvebu/pmsu.c +4 -1
index 454f0f9ede6b..8bf737fb3aac 100644
@@ -79,6 +79,8 @@ extern void armada_370_xp_cpu_resume(void);
 static unsigned long pmsu_mp_phys_base;
 static void __iomem *pmsu_mp_base;
 
+static void *mvebu_cpu_resume;
+
 static struct platform_device mvebu_v7_cpuidle_device = {
 	.name = "cpuidle-armada-370-xp",
 };
@@ -281,7 +283,7 @@ static int mvebu_v7_cpu_pm_notify(struct notifier_block *self,
 {
 	if (action == CPU_PM_ENTER) {
 		unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
-		mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume);
+		mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cpu_resume);
 	} else if (action == CPU_PM_EXIT) {
 		mvebu_v7_pmsu_idle_restore();
 	}
@@ -304,6 +306,7 @@ static __init bool armada_xp_cpuidle_init(void)
 		return false;
 	of_node_put(np);
 
+	mvebu_cpu_resume = armada_370_xp_cpu_resume;
 	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
 	return true;
 }
Signature · 1 line
1.8.1.2
#32 lore raw

PATCH 8/16 ARM: mvebu: Use a local variable to store the resume address

Dear Gregory CLEMENT,

arch/arm/mach-mvebu/pmsu.c static int mvebu_v7_cpu_pm_notify(struct notifier_block *self, · line 286

Quoted 11 lines · Gregory CLEMENT
arch/arm/mach-mvebu/pmsu.c +3 -1
+static void *mvebu_cpu_resume;
+
 static struct platform_device mvebu_v7_cpuidle_device = {
 	.name = "cpuidle-armada-370-xp",
 };
@@ -281,7 +283,7 @@ static int mvebu_v7_cpu_pm_notify(struct notifier_block *self,
 {
 	if (action == CPU_PM_ENTER) {
 		unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
-		mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume);
+		mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cpu_resume);

Instead of doing this in the CPU_PM_ENTER notifier, do we have a reason to not do it in the do_armada_370_xp_cpu_suspend() function, and then do_armada_38x_suspend() function respectively? Those functions are already SoC-specific, so surely, they already know whether the resume path should go through armada_370_xp_cpu_resume() or armada_38x_cpu_resume(), no?

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#33 lore raw

PATCH 8/16 ARM: mvebu: Use a local variable to store the resume address

Hi Thomas,

Quoted 14 lines · Thomas Petazzoni

Dear Gregory CLEMENT,

Quoted 10 lines · Gregory CLEMENT
arch/arm/mach-mvebu/pmsu.c +2 -1
+static void *mvebu_cpu_resume;
+
 static struct platform_device mvebu_v7_cpuidle_device = {
 	.name = "cpuidle-armada-370-xp",
 };
@@ -281,7 +283,7 @@ static int mvebu_v7_cpu_pm_notify(struct notifier_block *self,
 {
 	if (action == CPU_PM_ENTER) {
 		unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
-		mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume);
Quoted 8 lines

arch/arm/mach-mvebu/pmsu.c static int mvebu_v7_cpu_pm_notify(struct notifier_block *self, · line 286

Quoted 1 line
arch/arm/mach-mvebu/pmsu.c +1 -0
+		mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cpu_resume);

Instead of doing this in the CPU_PM_ENTER notifier, do we have a reason to not do it in the do_armada_370_xp_cpu_suspend() function, and then do_armada_38x_suspend() function respectively? Those functions are already SoC-specific, so surely, they already know whether the resume path should go through armada_370_xp_cpu_resume() or armada_38x_cpu_resume(), no?

Now that all this code is also part of pmsu and no more in the cpu dile driver. It should be possible. Let me see what it implies about the path code.

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#34 lore raw

PATCH 9/16 ARM: mvebu: Make the snoop disable optional in mvebu_v7_pmsu_idle_prepare

In reply to Gregory CLEMENT

On some mvebu v7 SoC (the ones which don't use PJ4B core) there is no such feature. So add a parameter in mvebu_v7_pmsu_idle_prepare function to make its use optional.

---
 arch/arm/mach-mvebu/pmsu.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)
arch/arm/mach-mvebu/pmsu.c +8 -6
index 8bf737fb3aac..a2869c5daeb0 100644
@@ -180,7 +180,7 @@ static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void)
 }
 
 /* No locking is needed because we only access per-CPU registers */
-static void mvebu_v7_pmsu_idle_prepare(bool deepidle)
+static void mvebu_v7_pmsu_idle_prepare(bool deepidle, bool snoopdis)
 {
 	unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
 	u32 reg;
@@ -211,15 +211,17 @@ static void mvebu_v7_pmsu_idle_prepare(bool deepidle)
 	reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ;
 	writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
 
-	/* Disable snoop disable by HW - SW is taking care of it */
-	reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
-	reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP;
-	writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
+	if (snoopdis) {
+		/* Disable snoop disable by HW - SW is taking care of it */
+		reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
+		reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP;
+		writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
+	}
 }
 
 static noinline int do_armada_xp_370_cpu_suspend(unsigned long deepidle)
 {
-	mvebu_v7_pmsu_idle_prepare(deepidle);
+	mvebu_v7_pmsu_idle_prepare(deepidle, true);
 
 	v7_exit_coherency_flush(all);
 
Signature · 1 line
1.8.1.2
#35 lore raw

PATCH 9/16 ARM: mvebu: Make the snoop disable optional in mvebu_v7_pmsu_idle_prepare

Gregory,

arch/arm/mach-mvebu/pmsu.c static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void) · line 183

Quoted 3 lines · Gregory CLEMENT

/* No locking is needed because we only access per-CPU registers */

arch/arm/mach-mvebu/pmsu.c +1 -1
-static void mvebu_v7_pmsu_idle_prepare(bool deepidle)
+static void mvebu_v7_pmsu_idle_prepare(bool deepidle, bool snoopdis)

I continue to find it odd to have more and more boolean arguments to a function to indicate what the function should do. It often indicates that the function should rather be split in smaller, fine-grained functions. Another sad consequence of using booleans is that the call sites of the functions can no longer be understood properly:

	mvebu_v7_pmsu_idle_prepare(false, true);
	mvebu_v7_pmsu_idle_prepare(true, true);
	mvebu_v7_pmsu_idle_prepare(false, false);

But oh well, it looks like it's the easiest solution here, and I admit it's convenient to have one function to the entire business of preparing for idle.

However, this change also badly conflicts with the CPU hotplug support that I have sent, and which is already part of linux-next, and for which Jason has sent a pull request to the arm-soc folks. See
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/tree/arch/arm/mach-mvebu/platsmp.c
for the usage of the armada_370_xp_pmsu_idle_enter() function.

Maybe your patch series should be based on mvebu/soc instead?

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#36 lore raw

PATCH 9/16 ARM: mvebu: Make the snoop disable optional in mvebu_v7_pmsu_idle_prepare

Hi Thomas,

Quoted 10 lines

arch/arm/mach-mvebu/pmsu.c static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void) · line 183

Quoted 3 lines

/* No locking is needed because we only access per-CPU registers */

arch/arm/mach-mvebu/pmsu.c +1 -1
-static void mvebu_v7_pmsu_idle_prepare(bool deepidle)
+static void mvebu_v7_pmsu_idle_prepare(bool deepidle, bool snoopdis)

I continue to find it odd to have more and more boolean arguments to a function to indicate what the function should do. It often indicates that the function should rather be split in smaller, fine-grained functions. Another sad consequence of using booleans is that the call sites of the functions can no longer be understood properly:

Quoted 7 lines
	mvebu_v7_pmsu_idle_prepare(false, true);
	mvebu_v7_pmsu_idle_prepare(true, true);
	mvebu_v7_pmsu_idle_prepare(false, false);

But oh well, it looks like it's the easiest solution here, and I admit it's convenient to have one function to the entire business of preparing for idle.

Maybe we can use flags, hence we use only one arguments, it became extensible, and more readable too. Something like

#define PMSU_IDLE_NO_FLAG 0
#define PMSU_IDLE_DEEPIDLE BIT(0)
#define PMSU_IDLE_SNOOPDIS BIT(1)

then we can have:
mvebu_v7_pmsu_idle_prepare(PMSU_IDLE_SNOOPDIS); mvebu_v7_pmsu_idle_prepare(PMSU_IDLE_DEEPIDLE | PMSU_IDLE_SNOOPDIS); mvebu_v7_pmsu_idle_prepare(PMSU_IDLE_NO_FLAG);

static void mvebu_v7_pmsu_idle_prepare(u32 flags)

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#37 lore raw

PATCH 9/16 ARM: mvebu: Make the snoop disable optional in mvebu_v7_pmsu_idle_prepare

Dear Gregory CLEMENT,

Quoted 7 lines · Gregory CLEMENT

Maybe we can use flags, hence we use only one arguments, it became extensible, and more readable too. Something like

#define PMSU_IDLE_NO_FLAG 0
#define PMSU_IDLE_DEEPIDLE BIT(0)
#define PMSU_IDLE_SNOOPDIS BIT(1)

Quoted 6 lines

then we can have:
mvebu_v7_pmsu_idle_prepare(PMSU_IDLE_SNOOPDIS); mvebu_v7_pmsu_idle_prepare(PMSU_IDLE_DEEPIDLE | PMSU_IDLE_SNOOPDIS); mvebu_v7_pmsu_idle_prepare(PMSU_IDLE_NO_FLAG);

static void mvebu_v7_pmsu_idle_prepare(u32 flags)

Yes, seems a good idea to me. Used "unsigned int" as the type for the flags argument, and maybe use PMSU_IDLE_NORMAL for 0 instead of NO_FLAG.

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#38 lore raw

PATCH 10/16 ARM: mvebu: Export the SCU address

In reply to Gregory CLEMENT

The SCU address will be needed in other files than the board file, for example in pmsu.c. So this patch adds a function allowing to get the SCU address.

---
 arch/arm/mach-mvebu/board-v7.c | 9 +++++++--
 arch/arm/mach-mvebu/common.h   | 2 ++
 2 files changed, 9 insertions(+), 2 deletions(-)
arch/arm/mach-mvebu/board-v7.c +7 -2
index 8bb742fdf5ca..4c1d955f51c0 100644
@@ -33,14 +33,14 @@
 #include "coherency.h"
 #include "mvebu-soc-id.h"
 
+static void __iomem *scu_base;
+
 /*
  * Enables the SCU when available. Obviously, this is only useful on
  * Cortex-A based SOCs, not on PJ4B based ones.
  */
 static void __init mvebu_scu_enable(void)
 {
-	void __iomem *scu_base;
-
 	struct device_node *np =
 		of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
 	if (np) {
@@ -50,6 +50,11 @@ static void __init mvebu_scu_enable(void)
 	}
 }
 
+void __iomem *mvebu_get_scu_base(void)
+{
+	return scu_base;
+}
+
 /*
  * Early versions of Armada 375 SoC have a bug where the BootROM
  * leaves an external data abort pending. The kernel is hit by this
arch/arm/mach-mvebu/common.h +2 -0
index 6ad62cf8352c..9beb0c45ba59 100644
@@ -25,4 +25,6 @@ void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr);
 
 void armada_xp_cpu_die(unsigned int cpu);
 
+void __iomem *mvebu_get_scu_base(void);
+
 #endif
Signature · 1 line
1.8.1.2
#39 lore raw

PATCH 11/16 ARM: mvebu: dts: Add CA9 MPcore SoC Controller node

In reply to Gregory CLEMENT

The CA9 MPcore SoC Control block allows to do some configuration that the SoC could use for a specific use case. In most cases the defaults case is enough. However there is few exception: for cpuidle we need to use the CA9 MPcore Reset Control register.

The documentation is also updated in the same time.

Cc devicetree at vger.kernel.org
---
 .../devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt | 14 ++++++++++++++
 arch/arm/boot/dts/armada-38x.dtsi                          |  5 +++++
 2 files changed, 19 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt
Documentation/devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt new file +14 -0
new file mode 100644
index 000000000000..0a2df51ba560
@@ -0,0 +1,14 @@
+Marvell Armada 38x CA9 MPcore SoC Controller
+============================================
+
+Required properties:
+
+- compatible: Should be "marvell,armada-380-mpcore-soc-ctrl".
+
+- reg: should be register base and length as documented in the
+  datasheet for the CA9 MPcore SoC Control registers
+
+mpcore-soc-ctrl at 20d20 {
+	compatible = "marvell,armada-380-mpcore-soc-ctrl";
+	reg = <0x20d20 0x6c>;
+};
arch/arm/boot/dts/armada-38x.dtsi +5 -0
index 689fa1a46728..242d0ecc99f3 100644
@@ -286,6 +286,11 @@
 				reg = <0x20800 0x10>;
 			};
 
+			mpcore-soc-ctrl at 20d20 {
+				compatible = "marvell,armada-380-mpcore-soc-ctrl";
+				reg = <0x20d20 0x6c>;
+			};
+
 			coherency-fabric at 21010 {
 				compatible = "marvell,armada-380-coherency-fabric";
 				reg = <0x21010 0x1c>;
Signature · 1 line
1.8.1.2
#40 lore raw

PATCH 11/16 ARM: mvebu: dts: Add CA9 MPcore SoC Controller node

Gregory,

Quoted 4 lines · Gregory CLEMENT

The CA9 MPcore SoC Control block allows to do some configuration that the SoC could use for a specific use case. In most cases the defaults case is enough. However there is few exception: for cpuidle we need to use the CA9 MPcore Reset Control register.

I'd reword this to something like:

"""
The CA9 MPcore SoC Control block is a set of registers that allows to configure certain internal aspects of the core blocks of the SoC (Cortex-A9, L2 cache controller, etc.). In most cases, the default values are fine so they aren't many reasons to touch those registers, but there is one exception: to support cpuidle on Armada 38x, we need to modify the value of the CA9 MPcore Reset Control register.

Therefore, this commit adds a new Device Tree binding for this hardware block, and uses this new binding for the Armada 38x Device Tree file.

"""

Quoted 14 lines
Cc devicetree at vger.kernel.org
---
 .../devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt | 14 ++++++++++++++
 arch/arm/boot/dts/armada-38x.dtsi                          |  5 +++++
 2 files changed, 19 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt
Documentation/devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt new file +0 -0
new file mode 100644
index 000000000000..0a2df51ba560

Documentation/devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt line 8

Quoted 8 lines
Documentation/devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt new file +8 -0
@@ -0,0 +1,14 @@
+Marvell Armada 38x CA9 MPcore SoC Controller
+============================================
+
+Required properties:
+
+- compatible: Should be "marvell,armada-380-mpcore-soc-ctrl".
+
+- reg: should be register base and length as documented in the

should be *the* register base and length

Quoted 12 lines
Documentation/devicetree/bindings/arm/armada-380-mpcore-soc-ctrl.txt new file +6 -0
+  datasheet for the CA9 MPcore SoC Control registers
+
+mpcore-soc-ctrl at 20d20 {
+	compatible = "marvell,armada-380-mpcore-soc-ctrl";
+	reg = <0x20d20 0x6c>;
+};
arch/arm/boot/dts/armada-38x.dtsi +0 -0
index 689fa1a46728..242d0ecc99f3 100644
@@ -286,6 +286,11 @@
 				reg = <0x20800 0x10>;

arch/arm/boot/dts/armada-38x.dtsi line 296

Quoted 10 lines
arch/arm/boot/dts/armada-38x.dtsi +5 -0
 			};
 
+			mpcore-soc-ctrl at 20d20 {
+				compatible = "marvell,armada-380-mpcore-soc-ctrl";
+				reg = <0x20d20 0x6c>;
+			};
+
 			coherency-fabric at 21010 {
 				compatible = "marvell,armada-380-coherency-fabric";
 				reg = <0x21010 0x1c>;

With those fixed:

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#41 lore raw

PATCH 11/16 ARM: mvebu: dts: Add CA9 MPcore SoC Controller node

Hi Thomas,

Quoted 20 lines · Gregory CLEMENT
Quoted 4 lines

The CA9 MPcore SoC Control block allows to do some configuration that the SoC could use for a specific use case. In most cases the defaults case is enough. However there is few exception: for cpuidle we need to use the CA9 MPcore Reset Control register.

I'd reword this to something like:

"""
The CA9 MPcore SoC Control block is a set of registers that allows to configure certain internal aspects of the core blocks of the SoC (Cortex-A9, L2 cache controller, etc.). In most cases, the default values are fine so they aren't many reasons to touch those registers, but there is one exception: to support cpuidle on Armada 38x, we need to modify the value of the CA9 MPcore Reset Control register.

Therefore, this commit adds a new Device Tree binding for this hardware block, and uses this new binding for the Armada 38x Device Tree file.

"""

[...]

Quoted 4 lines
Quoted 1 line

+- reg: should be register base and length as documented in the

should be *the* register base and length

			reg = <0x21010 0x1c>;
Quoted 4 lines

With those fixed:

I will apply your change.

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#42 lore raw

PATCH 12/16 cpuidle: mvebu: Rename the driver from armada-370-xp to mvebu-v7

In reply to Gregory CLEMENT

Actually this driver will be able to manage the cpuidle for more SoCs that Armada 370 ad XP. It will support Armada 38x and potentially Armada 375. This patch change the names accordingly to this behavior.

---
 arch/arm/mach-mvebu/pmsu.c              |  2 +-
 drivers/cpuidle/Kconfig.arm             |  6 +--
 drivers/cpuidle/Makefile                |  2 +-
 drivers/cpuidle/cpuidle-armada-370-xp.c | 93 ---------------------------------
 drivers/cpuidle/cpuidle-mvebu-v7.c      | 93 +++++++++++++++++++++++++++++++++
 5 files changed, 98 insertions(+), 98 deletions(-)
 delete mode 100644 drivers/cpuidle/cpuidle-armada-370-xp.c
 create mode 100644 drivers/cpuidle/cpuidle-mvebu-v7.c
arch/arm/mach-mvebu/pmsu.c +1 -1
index a2869c5daeb0..00ebd5638633 100644
@@ -82,7 +82,7 @@ static void __iomem *pmsu_mp_base;
 static void *mvebu_cpu_resume;
 
 static struct platform_device mvebu_v7_cpuidle_device = {
-	.name = "cpuidle-armada-370-xp",
+	.name = "cpuidle-mvebu-v7",
 };
 
 static struct of_device_id of_pmsu_table[] = {
drivers/cpuidle/Kconfig.arm +3 -3
index b6d69e899f5d..e4fc2fc66e9f 100644
@@ -1,11 +1,11 @@
 #
 # ARM CPU Idle drivers
 #
-config ARM_ARMADA_370_XP_CPUIDLE
-	bool "CPU Idle Driver for Armada 370/XP family processors"
+config ARM_MVEBU_V7_CPUIDLE
+	bool "CPU Idle Driver for mvebu v7 family processors"
 	depends on ARCH_MVEBU
 	help
-	  Select this to enable cpuidle on Armada 370/XP processors.
+	  Select this to enable cpuidle on Armada 370, 385 and XP processors.
 
 config ARM_BIG_LITTLE_CPUIDLE
 	bool "Support for ARM big.LITTLE processors"
drivers/cpuidle/Makefile +1 -1
index d8bb1ff72561..11edb31c55e9 100644
@@ -7,7 +7,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
 
 ##################################################################################
 # ARM SoC drivers
-obj-$(CONFIG_ARM_ARMADA_370_XP_CPUIDLE) += cpuidle-armada-370-xp.o
+obj-$(CONFIG_ARM_MVEBU_V7_CPUIDLE) += cpuidle-mvebu-v7.o
 obj-$(CONFIG_ARM_BIG_LITTLE_CPUIDLE)	+= cpuidle-big_little.o
 obj-$(CONFIG_ARM_CLPS711X_CPUIDLE)	+= cpuidle-clps711x.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)	+= cpuidle-calxeda.o
drivers/cpuidle/cpuidle-armada-370-xp.c deleted +0 -93

93 lines not on this page · raw message

drivers/cpuidle/cpuidle-mvebu-v7.c new file +93 -0

93 lines not on this page · raw message

Signature · 1 line
1.8.1.2
#43 lore raw

PATCH 12/16 cpuidle: mvebu: Rename the driver from armada-370-xp to mvebu-v7

Gregory,

Quoted 3 lines · Gregory CLEMENT

Actually this driver will be able to manage the cpuidle for more SoCs that Armada 370 ad XP. It will support Armada 38x and potentially Armada 375. This patch change the names accordingly to this behavior.

I think the last sentence should rather be something like: "This patch renames the driver as well as the functions and variables used in the driver".

I would also specifically mention the renaming of the driver that requires changing the pmsu.c file. It is worth mentioning that this rename, touching both drivers/cpuidle and arch/arm/mach-mvebu, may require some special handling in terms of patch merging (the patch mainly touches drivers/cpuidle so it should theoretically go through the cpuidle maintainer, but since the pmsu.c file is touched a lot by other patches, there will probably be lots of conflicts if this patch goes through the cpuidle tree). Surely something to mention as a comment in the patch, maybe to get the Acked-by of the cpuidle people and merge things through the mvebu and arm-soc trees.

drivers/cpuidle/Kconfig.arm line 5

Quoted 4 lines
drivers/cpuidle/Kconfig.arm +2 -2
-config ARM_ARMADA_370_XP_CPUIDLE
-	bool "CPU Idle Driver for Armada 370/XP family processors"
+config ARM_MVEBU_V7_CPUIDLE
+	bool "CPU Idle Driver for mvebu v7 family processors"

Actually, what worries me a bit of that Dove is a ARMv7 processor of the mvebu family, but which is not using this cpuidle driver. Do you expect Dove to be able to use this driver in the future?

drivers/cpuidle/Kconfig.arm line 8

Quoted 4 lines
drivers/cpuidle/Kconfig.arm +1 -1
 	depends on ARCH_MVEBU
 	help
-	  Select this to enable cpuidle on Armada 370/XP processors.
+	  Select this to enable cpuidle on Armada 370, 385 and XP processors.

385 -> 38x, because 380 and 385 are both capable of using this driver.

drivers/cpuidle/cpuidle-armada-370-xp.c

Quoted 5 lines
drivers/cpuidle/cpuidle-armada-370-xp.c deleted +0 -0
deleted file mode 100644
index a5fba0287bfb..000000000000

You haven't enabled rename detection in git? Or git isn't detecting the rename because of the number of changes in the file?

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#44 lore raw

PATCH 12/16 cpuidle: mvebu: Rename the driver from armada-370-xp to mvebu-v7

Hi Thomas,

Quoted 9 lines · Gregory CLEMENT
Quoted 3 lines

Actually this driver will be able to manage the cpuidle for more SoCs that Armada 370 ad XP. It will support Armada 38x and potentially Armada 375. This patch change the names accordingly to this behavior.

I think the last sentence should rather be something like: "This patch renames the driver as well as the functions and variables used in the driver".

Quoted 10 lines

I would also specifically mention the renaming of the driver that requires changing the pmsu.c file. It is worth mentioning that this rename, touching both drivers/cpuidle and arch/arm/mach-mvebu, may require some special handling in terms of patch merging (the patch mainly touches drivers/cpuidle so it should theoretically go through the cpuidle maintainer, but since the pmsu.c file is touched a lot by other patches, there will probably be lots of conflicts if this patch goes through the cpuidle tree). Surely something to mention as a comment in the patch, maybe to get the Acked-by of the cpuidle people and merge things through the mvebu and arm-soc trees.

I mentioned it in the cover letter but not with all the details.

Quoted 9 lines

drivers/cpuidle/Kconfig.arm line 5

Quoted 5 lines
drivers/cpuidle/Kconfig.arm +2 -2
-config ARM_ARMADA_370_XP_CPUIDLE
-	bool "CPU Idle Driver for Armada 370/XP family processors"
+config ARM_MVEBU_V7_CPUIDLE
+	bool "CPU Idle Driver for mvebu v7 family processors"

Actually, what worries me a bit of that Dove is a ARMv7 processor of the mvebu family, but which is not using this cpuidle driver. Do you expect Dove to be able to use this driver in the future?

Dove is also capable to go in deep idle mode as the other. The driver is now very generic all the SoC related code are not in the driver, so it would be possible. An argument against it, is that Armada 370, 38x and XP all use the PMSU manage the deep idle mode, wheres Dove use an other set of register.

Quoted 7 lines

drivers/cpuidle/Kconfig.arm line 8

Quoted 5 lines
drivers/cpuidle/Kconfig.arm +1 -1
 	depends on ARCH_MVEBU
 	help
-	  Select this to enable cpuidle on Armada 370/XP processors.
+	  Select this to enable cpuidle on Armada 370, 385 and XP processors.

385 -> 38x, because 380 and 385 are both capable of using this driver.

OK

Quoted 9 lines

drivers/cpuidle/cpuidle-armada-370-xp.c

Quoted 6 lines
drivers/cpuidle/cpuidle-armada-370-xp.c deleted +0 -0
deleted file mode 100644
index a5fba0287bfb..000000000000

You haven't enabled rename detection in git? Or git isn't detecting the rename because of the number of changes in the file?

I am not aware of this kind of configuration, internally for git I think it is the same thing, it is only the way he exposed this to the user that can be changed. However, it is true that I didn't use the -M flag with format-patch.

I will use it next time, because there also some change in the driver itself, it was mostly something like s/armada_370_xp/mvebu_v7/

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#45 lore raw

PATCH 13/16 cpuidle: mvebu: Move the description of the cpuidle states in the platform part

In reply to Gregory CLEMENT

In order to prepare the add of new SoCs supports for this cpuidle driver, this patch moves the description of the state in the platform part. Indeed the number of the cpuidle state, and the value of the flag used will vary depending of the SoC.

---
 arch/arm/mach-mvebu/pmsu.c         | 32 +++++++++++++++++++++++--
 drivers/cpuidle/cpuidle-mvebu-v7.c | 49 +++++++++++++-------------------------
 include/linux/mvebu-v7-cpuidle.h   | 24 +++++++++++++++++++
 3 files changed, 70 insertions(+), 35 deletions(-)
 create mode 100644 include/linux/mvebu-v7-cpuidle.h
arch/arm/mach-mvebu/pmsu.c +30 -2
index 00ebd5638633..9396839e162e 100644
@@ -19,15 +19,18 @@
 #define pr_fmt(fmt) "mvebu-pmsu: " fmt
 
 #include <linux/cpu_pm.h>
+#include <linux/cpuidle.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/mbus.h>
+#include <linux/mvebu-v7-cpuidle.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 #include <linux/resource.h>
 #include <linux/smp.h>
 #include <asm/cacheflush.h>
+#include <asm/cpuidle.h>
 #include <asm/cp15.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
@@ -299,17 +302,42 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = {
 
 static bool (*mvebu_v7_cpu_idle_init)(void);
 
+static struct mvebu_v7_cpuidle armada_xp_cpuidle = {
+	.mvebu_v7_idle_driver = {
+		.name			= "armada_xp_idle",
+		.states[0]		= ARM_CPUIDLE_WFI_STATE,
+		.states[1]		= {
+			.exit_latency		= 10,
+			.power_usage		= 50,
+			.target_residency	= 100,
+			.flags			= CPUIDLE_FLAG_TIME_VALID,
+			.name			= "Idle",
+			.desc			= "CPU power down",
+		},
+		.states[2]		= {
+			.exit_latency		= 100,
+			.power_usage		= 5,
+			.target_residency	= 1000,
+			.flags			= CPUIDLE_FLAG_TIME_VALID |
+			MVEBU_V7_FLAG_DEEP_IDLE,
+			.name			= "Deep idle",
+			.desc			= "CPU and L2 Fabric power down",
+		},
+		.state_count = 3,
+	},
+	.mvebu_v7_cpu_suspend = armada_xp_370_cpu_suspend,
+};
+
 static __init bool armada_xp_cpuidle_init(void)
 {
 	struct device_node *np;
-
 	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
 	if (!np)
 		return false;
 	of_node_put(np);
 
 	mvebu_cpu_resume = armada_370_xp_cpu_resume;
-	mvebu_v7_cpuidle_device.dev.platform_data = armada_xp_370_cpu_suspend;
+	mvebu_v7_cpuidle_device.dev.platform_data = &armada_xp_cpuidle;
 	return true;
 }
 
drivers/cpuidle/cpuidle-mvebu-v7.c +16 -33

79 lines not on this page · raw message

include/linux/mvebu-v7-cpuidle.h new file +24 -0
new file mode 100644
index 000000000000..28c8674292ad
@@ -0,0 +1,24 @@
+/*
+ * Marvell EBU cpuidle defintion
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Gregory CLEMENT <[email protected]>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ */
+
+#ifndef __LINUX_MVEBU_V7_CPUIDLE_H__
+#define __LINUX_MVEBU_V7_CPUIDLE_H__
+
+#define MVEBU_V7_FLAG_DEEP_IDLE	0x10000
+
+struct mvebu_v7_cpuidle {
+	struct cpuidle_driver mvebu_v7_idle_driver;
+	int (*mvebu_v7_cpu_suspend)(unsigned long);
+};
+
+#endif
Signature · 1 line
1.8.1.2
#46 lore raw

PATCH 13/16 cpuidle: mvebu: Move the description of the cpuidle states in the platform part

Dear Gregory CLEMENT,

Quoted 1 line · Gregory CLEMENT

In order to prepare the add of new SoCs supports for this cpuidle

"the add of new SoCs supports for this cpuidle" -> "the addition of the support for more SoCs in this cpuidle".

Quoted 3 lines

driver, this patch moves the description of the state in the platform part. Indeed the number of the cpuidle state, and the value of the flag used will vary depending of the SoC.

I actually don't really agree with the reasoning here. We can perfectly fine have several separate compatible strings, one for each SoC. We do this for pinctrl, for clocks, and for many other drivers. Why should it be different for the cpuidle driver? I know the function to enter idle will most likely implemented in arch/arm/mach-mvebu/ because those functions are generally too tightly coupled with a bunch of system registers changes, but the description of the different idle states can just as well be inside the cpuidle driver itself.

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#47 lore raw

PATCH 13/16 cpuidle: mvebu: Move the description of the cpuidle states in the platform part

Hi Thomas,

Quoted 9 lines
Quoted 1 line

In order to prepare the add of new SoCs supports for this cpuidle

"the add of new SoCs supports for this cpuidle" -> "the addition of the support for more SoCs in this cpuidle".

Quoted 3 lines

driver, this patch moves the description of the state in the platform part. Indeed the number of the cpuidle state, and the value of the flag used will vary depending of the SoC.

Quoted 8 lines

I actually don't really agree with the reasoning here. We can perfectly fine have several separate compatible strings, one for each SoC. We do this for pinctrl, for clocks, and for many other drivers. Why should it be different for the cpuidle driver? I know the function to enter idle will most likely implemented in arch/arm/mach-mvebu/ because those functions are generally too tightly coupled with a bunch of system registers changes, but the description of the different idle states can just as well be inside the cpuidle driver itself.

So that would means a different probe and driver name for each SOC? Indeed it is doable. With my solution adding the support for a new Soc won't modify the cpu idle driver itself, so the merge would be easier. But I admit that it is a misuse of the mach- directory.

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#48 lore raw

PATCH 14/16 ARM: mvebu: Add CPU idle support for Armada 370

In reply to Gregory CLEMENT

Unlike the Armada XP the Armada 370 always power done the L2 cache, so it have only 2 cpuidle states. Thanks to the previous patches, adding the support for this new SoCs required only the modification of the architecture specific part.

The message in case of failure to suspend the system was switched from warn to debug. Indeed due to the "slow exit process from the deep idle state" in Armada 370, this situation happens quite often. Using the _debug version avoids spamming the kernel logs, but still allows to enable it if needed.

---
 arch/arm/mach-mvebu/pmsu.c | 60 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 47 insertions(+), 13 deletions(-)
arch/arm/mach-mvebu/pmsu.c +47 -13
index 9396839e162e..bfd471538811 100644
@@ -250,7 +250,7 @@ static noinline int do_armada_xp_370_cpu_suspend(unsigned long deepidle)
 	"isb	"
 	: : "r" (0));
 
-	pr_warn("Failed to suspend the system\n");
+	pr_debug("Failed to suspend the system\n");
 
 	return 0;
 }
@@ -302,6 +302,24 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = {
 
 static bool (*mvebu_v7_cpu_idle_init)(void);
 
+static struct mvebu_v7_cpuidle armada_370_cpuidle = {
+	.mvebu_v7_idle_driver = {
+		.name			= "armada_370_idle",
+		.states[0]		= ARM_CPUIDLE_WFI_STATE,
+		.states[1]		= {
+			.exit_latency		= 100,
+			.power_usage		= 5,
+			.target_residency	= 1000,
+			.flags			= CPUIDLE_FLAG_TIME_VALID |
+			MVEBU_V7_FLAG_DEEP_IDLE,
+			.name			= "Deep Idle",
+			.desc			= "CPU and L2 Fabric power down",
+		},
+		.state_count = 2,
+	},
+	.mvebu_v7_cpu_suspend = armada_xp_370_cpu_suspend,
+};
+
 static struct mvebu_v7_cpuidle armada_xp_cpuidle = {
 	.mvebu_v7_idle_driver = {
 		.name			= "armada_xp_idle",
@@ -328,6 +346,31 @@ static struct mvebu_v7_cpuidle armada_xp_cpuidle = {
 	.mvebu_v7_cpu_suspend = armada_xp_370_cpu_suspend,
 };
 
+static __init bool armada_370_cpuidle_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+	if (!np)
+		return false;
+	of_node_put(np);
+
+	/*
+	 * On Armada 370, there is "a slow exit process from the deep
+	 * idle state due to heavy L1/L2 cache cleanup operations
+	 * performed by the BootROM software". To avoid this, we
+	 * replace the restart code of the bootrom by a a simple jump
+	 * to the boot address. Then the code located at this boot
+	 * address will take care of the initialization.
+	 */
+	mvebu_boot_addr_wa(ARMADA_370_CRYPT0_ENG_ID, pmsu_mp_phys_base +
+			PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));
+
+	mvebu_cpu_resume = armada_370_xp_cpu_resume;
+	mvebu_v7_cpuidle_device.dev.platform_data = &armada_370_cpuidle;
+	return true;
+}
+
 static __init bool armada_xp_cpuidle_init(void)
 {
 	struct device_node *np;
@@ -345,6 +388,9 @@ static struct of_device_id of_cpuidle_table[] __initdata = {
 	{ .compatible = "marvell,armadaxp",
 	  .data = (void *)armada_xp_cpuidle_init,
 	},
+	{ .compatible = "marvell,armada370",
+	  .data = (void *)armada_370_cpuidle_init,
+	},
 	{ /* end of list */ },
 };
 
@@ -373,18 +419,6 @@ static int __init mvebu_v7_cpu_pm_init(void)
 		return 0;
 	of_node_put(np);
 
-	/*
-	 * On Armada 370, there is "a slow exit process from the deep
-	 * idle state due to heavy L1/L2 cache cleanup operations
-	 * performed by the BootROM software". To avoid this, we
-	 * replace the restart code of the bootrom by a a simple jump
-	 * to the boot address. Then the code located at this boot
-	 * address will take care of the initialization.
-	 */
-	if (of_machine_is_compatible("marvell,armada370"))
-		mvebu_boot_addr_wa(ARMADA_370_CRYPT0_ENG_ID, pmsu_mp_phys_base +
-				PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));
-
 	mvebu_v7_pmsu_enable_l2_powerdown_onidle();
 	platform_device_register(&mvebu_v7_cpuidle_device);
 	cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier);
Signature · 1 line
1.8.1.2
#49 lore raw

PATCH 14/16 ARM: mvebu: Add CPU idle support for Armada 370

Dear Gregory CLEMENT,

Quoted 1 line · Gregory CLEMENT

Unlike the Armada XP the Armada 370 always power done the L2 cache, so

power -> powers
done -> down

Quoted 1 line

it have only 2 cpuidle states. Thanks to the previous patches, adding

have -> has.

Quoted 1 line

the support for this new SoCs required only the modification of the

required -> requires.

Quoted 1 line

architecture specific part.

May not be true if we move the cpuidle states back into the cpuidle driver, as I suggested in a comment to one of the previous patch.

Quoted 5 lines

The message in case of failure to suspend the system was switched from warn to debug. Indeed due to the "slow exit process from the deep idle state" in Armada 370, this situation happens quite often. Using the _debug version avoids spamming the kernel logs, but still allows to enable it if needed.

Is it really expected that the system fails to enter the idle state? I must say I don't really see the relation with the slow exit from deep idle state, because the do_armada_xp_370_cpu_suspend() function is only here to *enter* the idle state, so how is entering the deep idle state related to an issue when exiting the idle state?

Quoted 7 lines
arch/arm/mach-mvebu/pmsu.c +7 -0
+static struct mvebu_v7_cpuidle armada_370_cpuidle = {
+	.mvebu_v7_idle_driver = {
+		.name			= "armada_370_idle",
+		.states[0]		= ARM_CPUIDLE_WFI_STATE,
+		.states[1]		= {
+			.exit_latency		= 100,
+			.power_usage		= 5,

arch/arm/mach-mvebu/pmsu.c static struct notifier_block mvebu_v7_cpu_pm_notifier = { · line 321

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +10 -0
+			.target_residency	= 1000,
+			.flags			= CPUIDLE_FLAG_TIME_VALID |
+			MVEBU_V7_FLAG_DEEP_IDLE,
+			.name			= "Deep Idle",
+			.desc			= "CPU and L2 Fabric power down",
+		},
+		.state_count = 2,
+	},
+	.mvebu_v7_cpu_suspend = armada_xp_370_cpu_suspend,
+};

As I said, I'd prefer to see this in the cpuidle driver.

Quoted 51 lines
arch/arm/mach-mvebu/pmsu.c +29 -1
+
 static struct mvebu_v7_cpuidle armada_xp_cpuidle = {
 	.mvebu_v7_idle_driver = {
 		.name			= "armada_xp_idle",
@@ -328,6 +346,31 @@ static struct mvebu_v7_cpuidle armada_xp_cpuidle = {
 	.mvebu_v7_cpu_suspend = armada_xp_370_cpu_suspend,
 };
 
+static __init bool armada_370_cpuidle_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
+	if (!np)
+		return false;
+	of_node_put(np);
+
+	/*
+	 * On Armada 370, there is "a slow exit process from the deep
+	 * idle state due to heavy L1/L2 cache cleanup operations
+	 * performed by the BootROM software". To avoid this, we
+	 * replace the restart code of the bootrom by a a simple jump
+	 * to the boot address. Then the code located at this boot
+	 * address will take care of the initialization.
+	 */
+	mvebu_boot_addr_wa(ARMADA_370_CRYPT0_ENG_ID, pmsu_mp_phys_base +
+			PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));
+
+	mvebu_cpu_resume = armada_370_xp_cpu_resume;
+	mvebu_v7_cpuidle_device.dev.platform_data = &armada_370_cpuidle;
+	return true;
+}
+
 static __init bool armada_xp_cpuidle_init(void)
 {
 	struct device_node *np;
@@ -345,6 +388,9 @@ static struct of_device_id of_cpuidle_table[] __initdata = {
 	{ .compatible = "marvell,armadaxp",
 	  .data = (void *)armada_xp_cpuidle_init,
 	},
+	{ .compatible = "marvell,armada370",
+	  .data = (void *)armada_370_cpuidle_init,
+	},
 	{ /* end of list */ },
 };
 
@@ -373,18 +419,6 @@ static int __init mvebu_v7_cpu_pm_init(void)
 		return 0;
 	of_node_put(np);
 
-	/*

arch/arm/mach-mvebu/pmsu.c static int __init mvebu_v7_cpu_pm_init(void) · line 386

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +0 -10
-	 * On Armada 370, there is "a slow exit process from the deep
-	 * idle state due to heavy L1/L2 cache cleanup operations
-	 * performed by the BootROM software". To avoid this, we
-	 * replace the restart code of the bootrom by a a simple jump
-	 * to the boot address. Then the code located at this boot
-	 * address will take care of the initialization.
-	 */
-	if (of_machine_is_compatible("marvell,armada370"))
-		mvebu_boot_addr_wa(ARMADA_370_CRYPT0_ENG_ID, pmsu_mp_phys_base +
-				PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));

So we're almost entirely reverting/moving the code added by "[PATCH 05/16] ARM: mvebu: Add workaround for cpuidle support for Armada 370". Maybe there is an issue in your series, and the workaround for cpuidle support on Armada 370 should only be added in this patch, and not earlier?

arch/arm/mach-mvebu/pmsu.c static int __init mvebu_v7_cpu_pm_init(void) · line 424

Quoted 4 lines
arch/arm/mach-mvebu/pmsu.c +0 -1
-
 	mvebu_v7_pmsu_enable_l2_powerdown_onidle();
 	platform_device_register(&mvebu_v7_cpuidle_device);
 	cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier);

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#50 lore raw

PATCH 14/16 ARM: mvebu: Add CPU idle support for Armada 370

Hi Thomas,

Quoted 4 lines
Quoted 1 line

it have only 2 cpuidle states. Thanks to the previous patches, adding

have -> has.

Quoted 8 lines
Quoted 1 line

the support for this new SoCs required only the modification of the

required -> requires.

Quoted 1 line

architecture specific part.

May not be true if we move the cpuidle states back into the cpuidle driver, as I suggested in a comment to one of the previous patch.

Yes indeed :/

Quoted 7 lines
Quoted 6 lines

The message in case of failure to suspend the system was switched from warn to debug. Indeed due to the "slow exit process from the deep idle state" in Armada 370, this situation happens quite often. Using the _debug version avoids spamming the kernel logs, but still allows to enable it if needed.

Quoted 5 lines

Is it really expected that the system fails to enter the idle state? I must say I don't really see the relation with the slow exit from deep idle state, because the do_armada_xp_370_cpu_suspend() function is only here to *enter* the idle state, so how is entering the deep idle state related to an issue when exiting the idle state?

The issue is related to the cache management but not to the slow exit contrary to what I wrote.

We can see in the public datasheet, Figure 105:Deep Idle Simplified Flows. The last instruction done by software is WFI, but before being really in deep idle, the HW flush the L2 cache. This procedure is long and can take a lot of time. Any wakup event interrupt during the L2 flush in the power down procedure the HW can stop the flush and make the CPU return after the WFI.

I will update the explanation.

[...]

Quoted 9 lines
Quoted 9 lines
arch/arm/mach-mvebu/pmsu.c +0 -9
-	/*
-	 * On Armada 370, there is "a slow exit process from the deep
-	 * idle state due to heavy L1/L2 cache cleanup operations
-	 * performed by the BootROM software". To avoid this, we
-	 * replace the restart code of the bootrom by a a simple jump
-	 * to the boot address. Then the code located at this boot
-	 * address will take care of the initialization.
-	 */
-	if (of_machine_is_compatible("marvell,armada370"))
Quoted 8 lines

arch/arm/mach-mvebu/pmsu.c static int __init mvebu_v7_cpu_pm_init(void) · line 386

Quoted 2 lines
arch/arm/mach-mvebu/pmsu.c +0 -2
-		mvebu_boot_addr_wa(ARMADA_370_CRYPT0_ENG_ID, pmsu_mp_phys_base +
-				PMSU_BOOT_ADDR_REDIRECT_OFFSET(0));

So we're almost entirely reverting/moving the code added by "[PATCH 05/16] ARM: mvebu: Add workaround for cpuidle support for Armada 370". Maybe there is an issue in your series, and the workaround for cpuidle support on Armada 370 should only be added in this patch, and not earlier?

My idea when I kept "ARM: mvebu: Add workaround for cpuidle support for Armada 370", was to justify the introduction of the common function for the boot address work around. But it don't really make sens in the end.

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#51 lore raw

PATCH 15/16 ARM: mvebu: Add CPU idle support for Armada 38x

In reply to Gregory CLEMENT

Unlike the Armada XP and the Armada 370, this SoC uses a Cortex A9 core. Beside this, the main difference for the cpu idle is the way to handle the L2 cache and the use of SCU.

---
 arch/arm/mach-mvebu/pmsu.c    | 101 +++++++++++++++++++++++++++++++++++++++++-
 arch/arm/mach-mvebu/pmsu_ll.S |  14 ++++++
 2 files changed, 113 insertions(+), 2 deletions(-)
arch/arm/mach-mvebu/pmsu.c +99 -2
index bfd471538811..3e49fb73c3d5 100644
@@ -32,6 +32,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cpuidle.h>
 #include <asm/cp15.h>
+#include <asm/smp_scu.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/tlbflush.h>
@@ -66,6 +67,19 @@
 #define L2C_NFABRIC_PM_CTL		    0x4
 #define L2C_NFABRIC_PM_CTL_PWR_DOWN		BIT(20)
 
+/* PMSU delay registers */
+#define PMSU_POWERDOWN_DELAY		    0xF04
+#define PMSU_POWERDOWN_DELAY_PMU		BIT(1)
+#define PMSU_POWERDOWN_DELAY_MASK		0xFFFE
+
+#define PMSU_DFLT_ARMADA38X_DELAY	0x64
+
+/* CA9 MPcore SoC Control registers */
+
+#define MPCORE_RESET_CTL		    0x64
+#define MPCORE_RESET_CTL_L2			BIT(0)
+#define MPCORE_RESET_CTL_DEBUG			BIT(16)
+
 #define ARMADA_370_CRYPT0_ENG_ID	0x9
 #define CRYPT0_ENG_ATTR	0x1
 
@@ -78,10 +92,13 @@ extern void ll_disable_coherency(void);
 extern void ll_enable_coherency(void);
 
 extern void armada_370_xp_cpu_resume(void);
+extern void armada_38x_cpu_resume(void);
 
 static unsigned long pmsu_mp_phys_base;
 static void __iomem *pmsu_mp_base;
 
+static void __iomem *scu_base;
+
 static void *mvebu_cpu_resume;
 
 static struct platform_device mvebu_v7_cpuidle_device = {
@@ -151,6 +168,7 @@ static int __init mvebu_v7_pmsu_init(void)
 				np->full_name)) {
 		pr_err("unable to request region\n");
 		ret = -EBUSY;
+
 		goto out;
 	}
 
@@ -163,7 +181,6 @@ static int __init mvebu_v7_pmsu_init(void)
 		ret = -ENOMEM;
 		goto out;
 	}
-
  out:
 	of_node_put(np);
 	return ret;
@@ -260,6 +277,27 @@ static int armada_xp_370_cpu_suspend(unsigned long deepidle)
 	return cpu_suspend(deepidle, do_armada_xp_370_cpu_suspend);
 }
 
+static noinline int do_armada_38x_cpu_suspend(unsigned long deepidle)
+{
+	mvebu_v7_pmsu_idle_prepare(deepidle, false);
+	/*
+	 * Already flushed cache, but do it again as the outer cache
+	 * functions dirty the cache with spinlocks
+	 */
+	v7_exit_coherency_flush(louis);
+
+	scu_power_mode(scu_base, SCU_PM_POWEROFF);
+
+	cpu_do_idle();
+
+	return 1;
+}
+
+static int armada_38x_cpu_suspend(unsigned long deepidle)
+{
+	return cpu_suspend(false, do_armada_38x_cpu_suspend);
+}
+
 /* No locking is needed because we only access per-CPU registers */
 static noinline void mvebu_v7_pmsu_idle_restore(void)
 {
@@ -268,7 +306,6 @@ static noinline void mvebu_v7_pmsu_idle_restore(void)
 
 	if (pmsu_mp_base == NULL)
 		return;
-
 	/* cancel ask HW to power down the L2 Cache if possible */
 	reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
 	reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
@@ -320,6 +357,23 @@ static struct mvebu_v7_cpuidle armada_370_cpuidle = {
 	.mvebu_v7_cpu_suspend = armada_xp_370_cpu_suspend,
 };
 
+static struct mvebu_v7_cpuidle armada_38x_cpuidle = {
+	.mvebu_v7_idle_driver = {
+		.name			= "armada_38x_idle",
+		.states[0]		= ARM_CPUIDLE_WFI_STATE,
+		.states[1]		= {
+			.exit_latency		= 10,
+			.power_usage		= 5,
+			.target_residency	= 100,
+			.flags			= CPUIDLE_FLAG_TIME_VALID,
+			.name			= "Idle",
+			.desc			= "CPU and SCU power down",
+		},
+		.state_count = 2,
+	},
+	.mvebu_v7_cpu_suspend = armada_38x_cpu_suspend,
+};
+
 static struct mvebu_v7_cpuidle armada_xp_cpuidle = {
 	.mvebu_v7_idle_driver = {
 		.name			= "armada_xp_idle",
@@ -371,6 +425,46 @@ static __init bool armada_370_cpuidle_init(void)
 	return true;
 }
 
+static __init bool armada_38x_cpuidle_init(void)
+{
+	struct device_node *np;
+	void __iomem *mpsoc_base;
+	u32 reg;
+
+	np = of_find_compatible_node(NULL, NULL,
+				"marvell,armada-380-coherency-fabric");
+	if (!np)
+		return false;
+	of_node_put(np);
+
+	np = of_find_compatible_node(NULL, NULL,
+				"marvell,armada-380-mpcore-soc-ctrl");
+	if (!np)
+		return false;
+	mpsoc_base = of_iomap(np, 0);
+	WARN_ON(!mpsoc_base);
+
+	/* Set up reset mask when powering down the cpus */
+	reg = readl(mpsoc_base + MPCORE_RESET_CTL);
+	reg |= MPCORE_RESET_CTL_L2;
+	reg |= MPCORE_RESET_CTL_DEBUG;
+	writel(reg, mpsoc_base + MPCORE_RESET_CTL);
+	iounmap(mpsoc_base);
+	of_node_put(np);
+
+	/* Set up delay */
+	reg = readl(pmsu_mp_base + PMSU_POWERDOWN_DELAY);
+	reg &= ~PMSU_POWERDOWN_DELAY_MASK;
+	reg |= PMSU_DFLT_ARMADA38X_DELAY;
+	reg |= PMSU_POWERDOWN_DELAY_PMU;
+	writel(reg, pmsu_mp_base + PMSU_POWERDOWN_DELAY);
+
+	scu_base = mvebu_get_scu_base();
+	mvebu_cpu_resume = armada_38x_cpu_resume;
+	mvebu_v7_cpuidle_device.dev.platform_data = &armada_38x_cpuidle;
+	return true;
+}
+
 static __init bool armada_xp_cpuidle_init(void)
 {
 	struct device_node *np;
@@ -391,6 +485,9 @@ static struct of_device_id of_cpuidle_table[] __initdata = {
 	{ .compatible = "marvell,armada370",
 	  .data = (void *)armada_370_cpuidle_init,
 	},
+	{ .compatible = "marvell,armada380",
+	  .data = (void *)armada_38x_cpuidle_init,
+	},
 	{ /* end of list */ },
 };
 
arch/arm/mach-mvebu/pmsu_ll.S +14 -0
index 3b702a16bd3d..15b823dff61a 100644
@@ -23,6 +23,20 @@ ARM_BE8(setend	be )			@ go BE8 if entered LE
 	b	cpu_resume
 ENDPROC(armada_370_xp_cpu_resume)
 
+ENTRY(armada_38x_cpu_resume)
+	/* do we need it for Armada 38x*/
+ARM_BE8(setend	be )			@ go BE8 if entered LE
+	bl	v7_invalidate_l1
+	mrc     p15, 4, r1, c15, c0	@ get SCU base address
+	orr	r1, r1, #0x8		@ SCU CPU Power Status Register
+	mrc	15, 0, r0, cr0, cr0, 5	@ get the CPU ID
+	and	r0, r0, #15
+	add	r1, r1, r0
+	mov	r0, #0x0
+	strb	r0, [r1]		@ switch SCU power state to Normal mode
+	b	cpu_resume
+ENDPROC(armada_38x_cpu_resume)
+
 .global mvebu_boot_wa_start
 .global mvebu_boot_wa_end
 
Signature · 1 line
1.8.1.2
#52 lore raw

PATCH 15/16 ARM: mvebu: Add CPU idle support for Armada 38x

Gregory,

Quoted 2 lines · Gregory CLEMENT

Unlike the Armada XP and the Armada 370, this SoC uses a Cortex A9 core.

Isn't there some more details missing in this sentence? When I read it, at the end of the sentence, I'm wondering "and so what? what does this implies in terms of cpuidle support?".

Quoted 2 lines

Beside this, the main difference for the cpu idle is the way to handle the L2 cache and the use of SCU.

Beside -> Besides.

of SCU -> of the SCU

Quoted 1 line

+static void __iomem *scu_base;

It's really a shame that the SCU driver isn't a driver on its own, capable of storing the base address of the SCU instead of having to pass it around everywhere. But for sure it's not the point of this patch series to improve this as well.

arch/arm/mach-mvebu/pmsu.c static int __init mvebu_v7_pmsu_init(void) · line 171

Quoted 6 lines

static struct platform_device mvebu_v7_cpuidle_device = {

arch/arm/mach-mvebu/pmsu.c +1 -0
@@ -151,6 +168,7 @@ static int __init mvebu_v7_pmsu_init(void)
 				np->full_name)) {
 		pr_err("unable to request region\n");
 		ret = -EBUSY;
+

This change.

arch/arm/mach-mvebu/pmsu.c static int __init mvebu_v7_pmsu_init(void) · line 166

Quoted 8 lines
arch/arm/mach-mvebu/pmsu.c +0 -1
 		goto out;
 	}
 
@@ -163,7 +181,6 @@ static int __init mvebu_v7_pmsu_init(void)
 		ret = -ENOMEM;
 		goto out;
 	}
-

And this one look like spurious changes not related to the patch.

Quoted 9 lines
arch/arm/mach-mvebu/pmsu.c +2 -0
  out:
 	of_node_put(np);
 	return ret;
@@ -260,6 +277,27 @@ static int armada_xp_370_cpu_suspend(unsigned long deepidle)
 	return cpu_suspend(deepidle, do_armada_xp_370_cpu_suspend);
 }
 
+static noinline int do_armada_38x_cpu_suspend(unsigned long deepidle)
+{

arch/arm/mach-mvebu/pmsu.c static int armada_xp_370_cpu_suspend(unsigned long deepidle) · line 291

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +10 -0
+	mvebu_v7_pmsu_idle_prepare(deepidle, false);
+	/*
+	 * Already flushed cache, but do it again as the outer cache
+	 * functions dirty the cache with spinlocks
+	 */
+	v7_exit_coherency_flush(louis);
+
+	scu_power_mode(scu_base, SCU_PM_POWEROFF);
+
+	cpu_do_idle();

I see cpu_do_idle() does dsb() and wfi(), so why don't we use in the do_armada_370_xp_cpu_suspend() function ?

Review static int armada_xp_370_cpu_suspend(unsigned long deepidle) · line 293

Quoted 2 lines
(quoted diff) +2 -0
+
+	return 1;

You return 1 here, but in the do_armada_370_xp_cpu_suspend() function you return zero. Is the return value being used? Why use 0 in one case and 1 in the other?

Quoted 11 lines
arch/arm/mach-mvebu/pmsu.c +7 -0
+}
+
+static int armada_38x_cpu_suspend(unsigned long deepidle)
+{
+	return cpu_suspend(false, do_armada_38x_cpu_suspend);
+}
+
 /* No locking is needed because we only access per-CPU registers */
 static noinline void mvebu_v7_pmsu_idle_restore(void)
 {

arch/arm/mach-mvebu/pmsu.c static noinline void mvebu_v7_pmsu_idle_restore(void) · line 271

Quoted 4 lines
arch/arm/mach-mvebu/pmsu.c +0 -1
@@ -268,7 +306,6 @@ static noinline void mvebu_v7_pmsu_idle_restore(void)
 
 	if (pmsu_mp_base == NULL)
 		return;
-

Spurious change.

Quoted 13 lines
arch/arm/mach-mvebu/pmsu.c +6 -0
 	/* cancel ask HW to power down the L2 Cache if possible */
 	reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
 	reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
@@ -320,6 +357,23 @@ static struct mvebu_v7_cpuidle armada_370_cpuidle = {
 	.mvebu_v7_cpu_suspend = armada_xp_370_cpu_suspend,
 };
 
+static struct mvebu_v7_cpuidle armada_38x_cpuidle = {
+	.mvebu_v7_idle_driver = {
+		.name			= "armada_38x_idle",
+		.states[0]		= ARM_CPUIDLE_WFI_STATE,
+		.states[1]		= {
+			.exit_latency		= 10,

arch/arm/mach-mvebu/pmsu.c static struct mvebu_v7_cpuidle armada_370_cpuidle = { · line 375

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +10 -0
+			.power_usage		= 5,
+			.target_residency	= 100,
+			.flags			= CPUIDLE_FLAG_TIME_VALID,
+			.name			= "Idle",
+			.desc			= "CPU and SCU power down",
+		},
+		.state_count = 2,
+	},
+	.mvebu_v7_cpu_suspend = armada_38x_cpu_suspend,
+};

Should go to the cpuidle driver, IMO.

arch/arm/mach-mvebu/pmsu.c static __init bool armada_370_cpuidle_init(void) · line 428

Quoted 8 lines
arch/arm/mach-mvebu/pmsu.c +1 -0
 static struct mvebu_v7_cpuidle armada_xp_cpuidle = {
 	.mvebu_v7_idle_driver = {
 		.name			= "armada_xp_idle",
@@ -371,6 +425,46 @@ static __init bool armada_370_cpuidle_init(void)
 	return true;
 }
 
+static __init bool armada_38x_cpuidle_init(void)

As mentioned earlier, this function should return an 'int'.

arch/arm/mach-mvebu/pmsu.c static __init bool armada_370_cpuidle_init(void) · line 437

Quoted 9 lines
arch/arm/mach-mvebu/pmsu.c +9 -0
+{
+	struct device_node *np;
+	void __iomem *mpsoc_base;
+	u32 reg;
+
+	np = of_find_compatible_node(NULL, NULL,
+				"marvell,armada-380-coherency-fabric");
+	if (!np)
+		return false;
		return -ENODEV;

arch/arm/mach-mvebu/pmsu.c static __init bool armada_370_cpuidle_init(void) · line 443

Quoted 6 lines
arch/arm/mach-mvebu/pmsu.c +6 -0
+	of_node_put(np);
+
+	np = of_find_compatible_node(NULL, NULL,
+				"marvell,armada-380-mpcore-soc-ctrl");
+	if (!np)
+		return false;
		return -ENODEV;

arch/arm/mach-mvebu/pmsu.c static __init bool armada_370_cpuidle_init(void) · line 445

Quoted 2 lines
arch/arm/mach-mvebu/pmsu.c +2 -0
+	mpsoc_base = of_iomap(np, 0);
+	WARN_ON(!mpsoc_base);

WARN_ON() seems a bit weak for something that will make the next line crash the kernel. What about:

	if (!mpsoc_base)
		return -ENOMEM;

I think the of_node_put(np) should be here.

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +10 -0
+
+	/* Set up reset mask when powering down the cpus */
+	reg = readl(mpsoc_base + MPCORE_RESET_CTL);
+	reg |= MPCORE_RESET_CTL_L2;
+	reg |= MPCORE_RESET_CTL_DEBUG;
+	writel(reg, mpsoc_base + MPCORE_RESET_CTL);
+	iounmap(mpsoc_base);
+	of_node_put(np);
+
+	/* Set up delay */

arch/arm/mach-mvebu/pmsu.c static __init bool armada_370_cpuidle_init(void) · line 465

Quoted 10 lines
arch/arm/mach-mvebu/pmsu.c +10 -0
+	reg = readl(pmsu_mp_base + PMSU_POWERDOWN_DELAY);
+	reg &= ~PMSU_POWERDOWN_DELAY_MASK;
+	reg |= PMSU_DFLT_ARMADA38X_DELAY;
+	reg |= PMSU_POWERDOWN_DELAY_PMU;
+	writel(reg, pmsu_mp_base + PMSU_POWERDOWN_DELAY);
+
+	scu_base = mvebu_get_scu_base();
+	mvebu_cpu_resume = armada_38x_cpu_resume;
+	mvebu_v7_cpuidle_device.dev.platform_data = &armada_38x_cpuidle;
+	return true;
	return 0;

arch/arm/mach-mvebu/pmsu.c static struct of_device_id of_cpuidle_table[] __initdata = { · line 490

Quoted 12 lines
arch/arm/mach-mvebu/pmsu.c +5 -0
+}
+
 static __init bool armada_xp_cpuidle_init(void)
 {
 	struct device_node *np;
@@ -391,6 +485,9 @@ static struct of_device_id of_cpuidle_table[] __initdata = {
 	{ .compatible = "marvell,armada370",
 	  .data = (void *)armada_370_cpuidle_init,
 	},
+	{ .compatible = "marvell,armada380",
+	  .data = (void *)armada_38x_cpuidle_init,
+	},

As mentioned in the comments to a previous commit, I'm not sure using a match table is the best idea here.

Quoted 8 lines
arch/arm/mach-mvebu/pmsu.c +0 -0
 	{ /* end of list */ },
 };
 
arch/arm/mach-mvebu/pmsu_ll.S +0 -0
index 3b702a16bd3d..15b823dff61a 100644

arch/arm/mach-mvebu/pmsu_ll.S ARM_BE8(setend be ) @ go BE8 if entered LE · line 28

Quoted 6 lines
arch/arm/mach-mvebu/pmsu_ll.S +3 -0
@@ -23,6 +23,20 @@ ARM_BE8(setend	be )			@ go BE8 if entered LE
 	b	cpu_resume
 ENDPROC(armada_370_xp_cpu_resume)
 
+ENTRY(armada_38x_cpu_resume)
+	/* do we need it for Armada 38x*/
+ARM_BE8(setend	be )			@ go BE8 if entered LE

Yes, I believe we will need it. I'll try to do some testing and report.

Quoted 4 lines
arch/arm/mach-mvebu/pmsu_ll.S +4 -0
+	bl	v7_invalidate_l1
+	mrc     p15, 4, r1, c15, c0	@ get SCU base address
+	orr	r1, r1, #0x8		@ SCU CPU Power Status Register
+	mrc	15, 0, r0, cr0, cr0, 5	@ get the CPU ID

arch/arm/mach-mvebu/pmsu_ll.S ARM_BE8(setend be ) @ go BE8 if entered LE · line 42

Quoted 10 lines
arch/arm/mach-mvebu/pmsu_ll.S +7 -0
+	and	r0, r0, #15
+	add	r1, r1, r0
+	mov	r0, #0x0
+	strb	r0, [r1]		@ switch SCU power state to Normal mode
+	b	cpu_resume
+ENDPROC(armada_38x_cpu_resume)
+
 .global mvebu_boot_wa_start
 .global mvebu_boot_wa_end
 

Thanks!

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#53 lore raw

PATCH 15/16 ARM: mvebu: Add CPU idle support for Armada 38x

Hi Thomas,

Quoted 6 lines
Quoted 2 lines

Unlike the Armada XP and the Armada 370, this SoC uses a Cortex A9 core.

Isn't there some more details missing in this sentence? When I read it, at the end of the sentence, I'm wondering "and so what? what does this implies in terms of cpuidle support?".

Humm, actually, it the next sentence was wrongly formulate. Using a Cortex A9 implies(or at least encourage) the use of ARM L2 cache and of the SCU.

Quoted 3 lines
Quoted 3 lines

Beside this, the main difference for the cpu idle is the way to handle the L2 cache and the use of SCU.

[...]

Quoted 9 lines

arch/arm/mach-mvebu/pmsu.c static int __init mvebu_v7_pmsu_init(void) · line 171

Quoted 3 lines
arch/arm/mach-mvebu/pmsu.c +1 -0
 		pr_err("unable to request region\n");
 		ret = -EBUSY;
+

This change.

Quoted 3 lines
(quoted diff) +0 -0
 		goto out;
 	}
Quoted 7 lines

arch/arm/mach-mvebu/pmsu.c static int __init mvebu_v7_pmsu_init(void) · line 166

Quoted 5 lines
arch/arm/mach-mvebu/pmsu.c +0 -1
@@ -163,7 +181,6 @@ static int __init mvebu_v7_pmsu_init(void)
 		ret = -ENOMEM;
 		goto out;
 	}
-

And this one look like spurious changes not related to the patch.

yes of course.

Quoted 8 lines
Quoted 8 lines
arch/arm/mach-mvebu/pmsu.c +0 -0
  out:
 	of_node_put(np);
 	return ret;
@@ -260,6 +277,27 @@ static int armada_xp_370_cpu_suspend(unsigned long deepidle)
 	return cpu_suspend(deepidle, do_armada_xp_370_cpu_suspend);
 }
 
Quoted 15 lines

arch/arm/mach-mvebu/pmsu.c static int armada_xp_370_cpu_suspend(unsigned long deepidle) · line 291

Quoted 12 lines
arch/arm/mach-mvebu/pmsu.c +12 -0
+static noinline int do_armada_38x_cpu_suspend(unsigned long deepidle)
+{
+	mvebu_v7_pmsu_idle_prepare(deepidle, false);
+	/*
+	 * Already flushed cache, but do it again as the outer cache
+	 * functions dirty the cache with spinlocks
+	 */
+	v7_exit_coherency_flush(louis);
+
+	scu_power_mode(scu_base, SCU_PM_POWEROFF);
+
+	cpu_do_idle();

I see cpu_do_idle() does dsb() and wfi(), so why don't we use in the do_armada_370_xp_cpu_suspend() function ?

We can use cpu_do_idle() in do_armada_370_xp_cpu_suspend() too.

Quoted 7 lines

Review static int armada_xp_370_cpu_suspend(unsigned long deepidle) · line 293

Quoted 3 lines
(quoted diff) +2 -0
+
+	return 1;

You return 1 here, but in the do_armada_370_xp_cpu_suspend() function you return zero. Is the return value being used? Why use 0 in one case and 1 in the other?

return 1 means error. But I think it was a nasty trick to not enter in the CPU_PM_EXIT case. I forgot to go back on this, once the cpu idle was working on Armada 38x. I will take care of it in the next series.

[...]

Quoted 27 lines

arch/arm/mach-mvebu/pmsu.c static __init bool armada_370_cpuidle_init(void) · line 437

Quoted 9 lines
arch/arm/mach-mvebu/pmsu.c +9 -0
+{
+	struct device_node *np;
+	void __iomem *mpsoc_base;
+	u32 reg;
+
+	np = of_find_compatible_node(NULL, NULL,
+				"marvell,armada-380-coherency-fabric");
+	if (!np)
+		return false;
		return -ENODEV;

arch/arm/mach-mvebu/pmsu.c static __init bool armada_370_cpuidle_init(void) · line 443

Quoted 6 lines
arch/arm/mach-mvebu/pmsu.c +6 -0
+	of_node_put(np);
+
+	np = of_find_compatible_node(NULL, NULL,
+				"marvell,armada-380-mpcore-soc-ctrl");
+	if (!np)
+		return false;
		return -ENODEV;

arch/arm/mach-mvebu/pmsu.c static __init bool armada_370_cpuidle_init(void) · line 445

Quoted 2 lines
arch/arm/mach-mvebu/pmsu.c +2 -0
+	mpsoc_base = of_iomap(np, 0);
+	WARN_ON(!mpsoc_base);

WARN_ON() seems a bit weak for something that will make the next line crash the kernel. What about:

Quoted 4 lines
	if (!mpsoc_base)
		return -ENOMEM;

I think the of_node_put(np) should be here.

OK

Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#54 lore raw

PATCH 15/16 ARM: mvebu: Add CPU idle support for Armada 38x

In reply to Gregory CLEMENT

Dear Gregory CLEMENT,

arch/arm/mach-mvebu/pmsu_ll.S ARM_BE8(setend be ) @ go BE8 if entered LE · line 28

Quoted 3 lines · Gregory CLEMENT
arch/arm/mach-mvebu/pmsu_ll.S +3 -0
+ENTRY(armada_38x_cpu_resume)
+	/* do we need it for Armada 38x*/
+ARM_BE8(setend	be )			@ go BE8 if entered LE

We logically needed this, but I've confirmed, and indeed it is really needed for cpuidle to work properly on Armada 38x in big-endian configuration.

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#55 lore raw

PATCH 15/16 ARM: mvebu: Add CPU idle support for Armada 38x

Hi Thomas,

Quoted 10 lines · Gregory CLEMENT

arch/arm/mach-mvebu/pmsu_ll.S ARM_BE8(setend be ) @ go BE8 if entered LE · line 28

Quoted 4 lines
arch/arm/mach-mvebu/pmsu_ll.S +3 -0
+ENTRY(armada_38x_cpu_resume)
+	/* do we need it for Armada 38x*/
+ARM_BE8(setend	be )			@ go BE8 if entered LE

We logically needed this, but I've confirmed, and indeed it is really needed for cpuidle to work properly on Armada 38x in big-endian configuration.

OK
Thanks,

Gregory

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#56 lore raw

PATCH 16/16 ARM: mvebu: defconfig: Enable CPU Idle support in mvebu_v7_defconfig

In reply to Gregory CLEMENT

mvebu SoCs such as Armada 370, Armada XP or Armada 38x now support CPU Idle so let's add it in the default configuration.

---
 arch/arm/configs/mvebu_v7_defconfig | 2 ++
 1 file changed, 2 insertions(+)
arch/arm/configs/mvebu_v7_defconfig +2 -0
index e11170e37442..b174072cabd8 100644
@@ -28,6 +28,8 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CPU_IDLE=y
+CONFIG_ARM_MVEBU_V7_CPUIDLE=y
 CONFIG_VFP=y
 CONFIG_NET=y
 CONFIG_INET=y
Signature · 1 line
1.8.1.2
#57 lore raw

cover CPU Idle for Armada 370 and Armada 38x

In reply to Gregory CLEMENT

Gregory,

Quoted 6 lines · Gregory CLEMENT

This patch set adds the CPU Idle support for two mvebu SoCs: the Armada 370 and the Armada 38x. As there are common parts with the current support of cpuidle of the Armada XP. I made the code even more generic. Thanks to this change, adding a new SoC is now only done in the architecture specific part and we won't have to touch the cpuidle driver anymore for this.

I'd like to do some testing of this patch series, especially in big endian situations. Do you have a Git repository where this version was pushed?

Thanks,

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#58 lore raw

cover CPU Idle for Armada 370 and Armada 38x

Quoted 11 lines · Thomas Petazzoni

Gregory,

Quoted 6 lines · Gregory CLEMENT

This patch set adds the CPU Idle support for two mvebu SoCs: the Armada 370 and the Armada 38x. As there are common parts with the current support of cpuidle of the Armada XP. I made the code even more generic. Thanks to this change, adding a new SoC is now only done in the architecture specific part and we won't have to touch the cpuidle driver anymore for this.

Quoted 3 lines

I'd like to do some testing of this patch series, especially in big endian situations. Do you have a Git repository where this version was pushed?

Yes sure, the branch CPU-Idle-mvebu-next-3.16-rc2-V1 on
https://github.com/MISL-EBU-System-SW/mainline-public.git

Quoted 5 lines

Thanks,

Thomas

Signature · 4 lines
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
#59 lore raw

cover CPU Idle for Armada 370 and Armada 38x

Dear Gregory CLEMENT,

Quoted 6 lines · Gregory CLEMENT
Quoted 3 lines

I'd like to do some testing of this patch series, especially in big endian situations. Do you have a Git repository where this version was pushed?

Yes sure, the branch CPU-Idle-mvebu-next-3.16-rc2-V1 on
https://github.com/MISL-EBU-System-SW/mainline-public.git

Ok, I've tested the following cases:

* Armada XP LE and BE: it shouldn't be affected by your patch series, and indeed, it works fine.

* Armada 370 LE worked fine.

* Armada 370 BE didn't work, I had to fix the code in pmsu.c/pmsu_ll.S. I already replied to the appropriate patch to indicate what was wrong.

* Armada 375 LE worked fine. Armada 375 BE was also affected by the same issue as Armada 370 BE because they use the same work-around for the boot issue (Armada 375 Z1 of course, since Armada 375 A0 is not affected). With the fix added for big-endian, Armada 375 BE works again (i.e its SMP initialization works).

* Armada 38x LE and BE worked fine (there was a completely unrelated issue in the SMP initialization of 38x in BE, I'll sent a patch shortly for this).

So all in all, in terms of testing, despite the minor fix for the BE configuration, it looks good to me.

Thanks!

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com