2013-04-19 10:48:15

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 01/15] powerpc/85xx: cache operations for Freescale SoCs based on BOOK3E

These cache operations support Freescale SoCs based on BOOK3E.
Move L1 cache operations to fsl_booke_cache.S in order to maintain
easily. And, add cache operations for backside L2 cache and platform cache.

The backside L2 cache appears on e500mc and e5500 core. The platform cache
supported by this patch is L2 Look-Aside Cache, which appears on SoCs
with e500v1/e500v2 core, such as MPC8572, P1020, etc.

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
---
arch/powerpc/include/asm/cacheflush.h | 8 ++
arch/powerpc/kernel/Makefile | 1 +
arch/powerpc/kernel/fsl_booke_cache.S | 210 +++++++++++++++++++++++++++++++++
arch/powerpc/kernel/head_fsl_booke.S | 74 ------------
4 files changed, 219 insertions(+), 74 deletions(-)
create mode 100644 arch/powerpc/kernel/fsl_booke_cache.S

diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index b843e35..bc3f937 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -32,6 +32,14 @@ extern void flush_dcache_page(struct page *page);

extern void __flush_disable_L1(void);

+#ifdef CONFIG_FSL_SOC_BOOKE
+void flush_dcache_L1(void);
+void flush_backside_L2_cache(void);
+void disable_backside_L2_cache(void);
+void flush_disable_L2(void);
+void invalidate_enable_L2(void);
+#endif
+
extern void __flush_icache_range(unsigned long, unsigned long);
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index f960a79..4acf739 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -87,6 +87,7 @@ extra-$(CONFIG_8xx) := head_8xx.o
extra-y += vmlinux.lds

obj-$(CONFIG_RELOCATABLE_PPC32) += reloc_32.o
+obj-$(CONFIG_FSL_SOC_BOOKE) += fsl_booke_cache.o

obj-$(CONFIG_PPC32) += entry_32.o setup_32.o
obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o
diff --git a/arch/powerpc/kernel/fsl_booke_cache.S b/arch/powerpc/kernel/fsl_booke_cache.S
new file mode 100644
index 0000000..232c47b
--- /dev/null
+++ b/arch/powerpc/kernel/fsl_booke_cache.S
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2009-2013 Freescale Semiconductor, Inc.
+ * Scott Wood <[email protected]>
+ * Dave Liu <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+ .section .text
+
+/******** L1 Cache ********/
+
+/* flush L1 d-cache */
+_GLOBAL(flush_dcache_L1)
+ mfspr r3,SPRN_L1CFG0
+
+ rlwinm r5,r3,9,3 /* Extract cache block size */
+ twlgti r5,1 /* Only 32 and 64 byte cache blocks
+ * are currently defined.
+ */
+ li r4,32
+ subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) -
+ * log2(number of ways)
+ */
+ slw r5,r4,r5 /* r5 = cache block size */
+
+ rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */
+ mulli r7,r7,13 /* An 8-way cache will require 13
+ * loads per set.
+ */
+ slw r7,r7,r6
+
+ /* save off HID0 and set DCFA */
+ mfspr r8,SPRN_HID0
+ ori r9,r8,HID0_DCFA@l
+ mtspr SPRN_HID0,r9
+ isync
+
+ LOAD_REG_IMMEDIATE(r4, KERNELBASE)
+ mtctr r7
+
+1: lwz r3,0(r4) /* Load... */
+ add r4,r4,r5
+ bdnz 1b
+
+ msync
+ LOAD_REG_IMMEDIATE(r4, KERNELBASE)
+ mtctr r7
+
+1: dcbf 0,r4 /* ...and flush. */
+ add r4,r4,r5
+ bdnz 1b
+
+ /* restore HID0 */
+ mtspr SPRN_HID0,r8
+ isync
+
+ blr
+
+/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
+_GLOBAL(__flush_disable_L1)
+ mflr r10
+ bl flush_dcache_L1 /* Flush L1 d-cache */
+ mtlr r10
+
+ msync
+ mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
+ li r5, 2
+ rlwimi r4, r5, 0, 3
+
+ msync
+ isync
+ mtspr SPRN_L1CSR0, r4
+ isync
+
+ msync
+1: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
+ andi. r4, r4, 2
+ bne 1b
+
+ msync
+ mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
+ li r5, 2
+ rlwimi r4, r5, 0, 3
+
+ msync
+ isync
+ mtspr SPRN_L1CSR1, r4
+ isync
+ msync
+
+ blr
+
+/******** Backside L2 Cache ********/
+
+#define SVR_P2040 0x821000
+
+need_L2_cache:
+ /* skip L2 cache on P2040/P2040E as they have no L2 cache */
+ mfspr r3, SPRN_SVR
+ /* shift right by 8 bits and clear E bit of SVR */
+ rlwinm r4, r3, 24, ~0x800
+
+ lis r3, SVR_P2040@h
+ ori r3, r3, SVR_P2040@l
+ cmpw r4, r3
+ beq 1f
+
+ /* If L2 cache is disabled, skip it */
+ mfspr r3, SPRN_L2CSR0
+ andis. r3, r3, L2CSR0_L2E@h
+ beq 1f
+
+ li r3, 0
+ blr
+1:
+ li r3, 1
+ blr
+
+/* flush backside L2 cache */
+_GLOBAL(flush_backside_L2_cache)
+ mflr r10
+ bl need_L2_cache
+ mtlr r10
+ cmpwi r3, 0
+ bne 2f
+
+__flush_backside_L2_cache:
+ /* Flush the L2 cache */
+ mfspr r3, SPRN_L2CSR0
+ ori r3, r3, L2CSR0_L2FL@l
+ msync
+ isync
+ mtspr SPRN_L2CSR0,r3
+ isync
+1:
+ mfspr r3,SPRN_L2CSR0
+ andi. r3, r3, L2CSR0_L2FL@l
+ bne 1b
+2:
+ blr
+
+/* flush and disable backside L2 cache */
+_GLOBAL(disable_backside_L2_cache)
+ mflr r10
+ bl need_L2_cache
+ mtlr r10
+ cmpwi r3, 0
+ bne 1f
+
+ mflr r10
+ bl __flush_backside_L2_cache
+ mtlr r10
+
+ /* disable L2 cache */
+ li r3, 0
+ msync
+ isync
+ mtspr SPRN_L2CSR0, r3
+ isync
+1:
+ blr
+
+/******** Platform Cache ********/
+
+#define L2CTL_L2E 0x80000000
+#define L2CTL_L2I 0x40000000
+
+/* r3 = base address of L2 controller registers */
+_GLOBAL(flush_disable_L2)
+ /* It's a write-through cache, so only invalidation is needed. */
+ mbar
+ isync
+ lwz r4, 0(r3)
+ li r5, 1
+ rlwimi r4, r5, 30, L2CTL_L2E | L2CTL_L2I
+ stw r4, 0(r3)
+
+ /* Wait for the invalidate to finish */
+1: lwz r4, 0(r3)
+ andis. r4, r4, L2CTL_L2I@h
+ bne 1b
+ mbar
+
+ blr
+
+/* r3 = base address of L2 controller registers */
+_GLOBAL(invalidate_enable_L2)
+ mbar
+ isync
+ lwz r4, 0(r3)
+ li r5, 3
+ rlwimi r4, r5, 30, L2CTL_L2E | L2CTL_L2I
+ stw r4, 0(r3)
+
+ /* Wait for the invalidate to finish */
+1: lwz r4, 0(r3)
+ andis. r4, r4, L2CTL_L2I@h
+ bne 1b
+ mbar
+
+ blr
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 6f62a73..58925b6 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -987,80 +987,6 @@ _GLOBAL(set_context)
isync /* Force context change */
blr

-_GLOBAL(flush_dcache_L1)
- mfspr r3,SPRN_L1CFG0
-
- rlwinm r5,r3,9,3 /* Extract cache block size */
- twlgti r5,1 /* Only 32 and 64 byte cache blocks
- * are currently defined.
- */
- li r4,32
- subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) -
- * log2(number of ways)
- */
- slw r5,r4,r5 /* r5 = cache block size */
-
- rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */
- mulli r7,r7,13 /* An 8-way cache will require 13
- * loads per set.
- */
- slw r7,r7,r6
-
- /* save off HID0 and set DCFA */
- mfspr r8,SPRN_HID0
- ori r9,r8,HID0_DCFA@l
- mtspr SPRN_HID0,r9
- isync
-
- lis r4,KERNELBASE@h
- mtctr r7
-
-1: lwz r3,0(r4) /* Load... */
- add r4,r4,r5
- bdnz 1b
-
- msync
- lis r4,KERNELBASE@h
- mtctr r7
-
-1: dcbf 0,r4 /* ...and flush. */
- add r4,r4,r5
- bdnz 1b
-
- /* restore HID0 */
- mtspr SPRN_HID0,r8
- isync
-
- blr
-
-/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
-_GLOBAL(__flush_disable_L1)
- mflr r10
- bl flush_dcache_L1 /* Flush L1 d-cache */
- mtlr r10
-
- mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
- li r5, 2
- rlwimi r4, r5, 0, 3
-
- msync
- isync
- mtspr SPRN_L1CSR0, r4
- isync
-
-1: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
- andi. r4, r4, 2
- bne 1b
-
- mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
- li r5, 2
- rlwimi r4, r5, 0, 3
-
- mtspr SPRN_L1CSR1, r4
- isync
-
- blr
-
#ifdef CONFIG_SMP
/* When we get here, r24 needs to hold the CPU # */
.globl __secondary_start
--
1.7.3


2013-04-19 10:48:22

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 04/15] pm: add power node to dts

The Power Management device tree stub indicated that the platform
supports Power Management feature.

Signed-off-by: Zhao Chenhui <[email protected]>
---
arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi | 14 ++++++-
arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi | 2 +
arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi | 2 +
arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi | 2 +
arch/powerpc/boot/dts/fsl/p1010si-post.dtsi | 8 ++++
arch/powerpc/boot/dts/fsl/p1020si-post.dtsi | 5 +++
arch/powerpc/boot/dts/fsl/p1021si-post.dtsi | 5 +++
arch/powerpc/boot/dts/fsl/p1022si-post.dtsi | 11 ++++--
arch/powerpc/boot/dts/fsl/p2020si-post.dtsi | 14 +++++++
arch/powerpc/boot/dts/fsl/pq3-power.dtsi | 48 +++++++++++++++++++++++++
10 files changed, 106 insertions(+), 5 deletions(-)
create mode 100644 arch/powerpc/boot/dts/fsl/pq3-power.dtsi

diff --git a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
index c8b2daa..900f117 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
@@ -199,6 +199,10 @@

/include/ "pq3-dma-0.dtsi"
/include/ "pq3-etsec1-0.dtsi"
+ enet0: ethernet@24000 {
+ fsl,wake-on-filer;
+ fsl,pmc-handle = <&etsec1_clk>;
+ };
/include/ "pq3-etsec1-timer-0.dtsi"

usb@22000 {
@@ -222,9 +226,10 @@
};

/include/ "pq3-etsec1-2.dtsi"
-
- ethernet@26000 {
+ enet2: ethernet@26000 {
cell-index = <1>;
+ fsl,wake-on-filer;
+ fsl,pmc-handle = <&etsec3_clk>;
};

usb@2b000 {
@@ -249,4 +254,9 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
+ power@e0070 {
+ compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
+ };
};
diff --git a/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
index b68eb11..ea7416a 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
@@ -188,4 +188,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
index 579d76c..dddb737 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
@@ -156,4 +156,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
index d44e25a..7313351 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
@@ -193,4 +193,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
index af12ead..01c8c33 100644
--- a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
@@ -171,6 +171,8 @@

/include/ "pq3-etsec2-0.dtsi"
enet0: ethernet@b0000 {
+ fsl,pmc-handle = <&etsec1_clk>;
+
queue-group@b0000 {
fsl,rx-bit-map = <0xff>;
fsl,tx-bit-map = <0xff>;
@@ -179,6 +181,8 @@

/include/ "pq3-etsec2-1.dtsi"
enet1: ethernet@b1000 {
+ fsl,pmc-handle = <&etsec2_clk>;
+
queue-group@b1000 {
fsl,rx-bit-map = <0xff>;
fsl,tx-bit-map = <0xff>;
@@ -187,6 +191,8 @@

/include/ "pq3-etsec2-2.dtsi"
enet2: ethernet@b2000 {
+ fsl,pmc-handle = <&etsec3_clk>;
+
queue-group@b2000 {
fsl,rx-bit-map = <0xff>;
fsl,tx-bit-map = <0xff>;
@@ -199,4 +205,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
index 68cc5e7..410e6e5 100644
--- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
@@ -162,14 +162,17 @@

/include/ "pq3-etsec2-0.dtsi"
enet0: enet0_grp2: ethernet@b0000 {
+ fsl,pmc-handle = <&etsec1_clk>;
};

/include/ "pq3-etsec2-1.dtsi"
enet1: enet1_grp2: ethernet@b1000 {
+ fsl,pmc-handle = <&etsec2_clk>;
};

/include/ "pq3-etsec2-2.dtsi"
enet2: enet2_grp2: ethernet@b2000 {
+ fsl,pmc-handle = <&etsec3_clk>;
};

global-utilities@e0000 {
@@ -177,6 +180,8 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};

/include/ "pq3-etsec2-grp2-0.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
index adb82fd..02df574 100644
--- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
@@ -158,14 +158,17 @@

/include/ "pq3-etsec2-0.dtsi"
enet0: enet0_grp2: ethernet@b0000 {
+ fsl,pmc-handle = <&etsec1_clk>;
};

/include/ "pq3-etsec2-1.dtsi"
enet1: enet1_grp2: ethernet@b1000 {
+ fsl,pmc-handle = <&etsec2_clk>;
};

/include/ "pq3-etsec2-2.dtsi"
enet2: enet2_grp2: ethernet@b2000 {
+ fsl,pmc-handle = <&etsec3_clk>;
};

global-utilities@e0000 {
@@ -173,6 +176,8 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};

&qe {
diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
index e179803..c5343e7 100644
--- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
@@ -223,10 +223,14 @@

/include/ "pq3-etsec2-0.dtsi"
enet0: enet0_grp2: ethernet@b0000 {
+ fsl,wake-on-filer;
+ fsl,pmc-handle = <&etsec1_clk>;
};

/include/ "pq3-etsec2-1.dtsi"
enet1: enet1_grp2: ethernet@b1000 {
+ fsl,wake-on-filer;
+ fsl,pmc-handle = <&etsec2_clk>;
};

global-utilities@e0000 {
@@ -235,9 +239,10 @@
fsl,has-rstcr;
};

- power@e0070{
- compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
- reg = <0xe0070 0x20>;
+/include/ "pq3-power.dtsi"
+ power@e0070 {
+ compatible = "fsl,p1022-pmc", "fsl,mpc8536-pmc",
+ "fsl,mpc8548-pmc";
};

};
diff --git a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
index 884e01b..2c4787c 100644
--- a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
@@ -175,6 +175,10 @@
compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
};
/include/ "pq3-etsec1-0.dtsi"
+ enet0: ethernet@24000 {
+ fsl,pmc-handle = <&etsec1_clk>;
+
+ };
/include/ "pq3-etsec1-timer-0.dtsi"

ptp_clock@24e00 {
@@ -183,7 +187,15 @@


/include/ "pq3-etsec1-1.dtsi"
+ enet1: ethernet@25000 {
+ fsl,pmc-handle = <&etsec2_clk>;
+ };
+
/include/ "pq3-etsec1-2.dtsi"
+ enet2: ethernet@26000 {
+ fsl,pmc-handle = <&etsec3_clk>;
+ };
+
/include/ "pq3-esdhc-0.dtsi"
sdhc@2e000 {
compatible = "fsl,p2020-esdhc", "fsl,esdhc";
@@ -198,4 +210,6 @@
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
+
+/include/ "pq3-power.dtsi"
};
diff --git a/arch/powerpc/boot/dts/fsl/pq3-power.dtsi b/arch/powerpc/boot/dts/fsl/pq3-power.dtsi
new file mode 100644
index 0000000..5a760b3
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-power.dtsi
@@ -0,0 +1,48 @@
+/*
+ * PQ3 Power Management device tree stub
+ *
+ * Copyright 2012-2013 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+power@e0070 {
+ compatible = "fsl,mpc8548-pmc";
+ reg = <0xe0070 0x20>;
+
+ etsec1_clk: soc-clk@24 {
+ fsl,pmcdr-mask = <0x00000080>;
+ };
+ etsec2_clk: soc-clk@25 {
+ fsl,pmcdr-mask = <0x00000040>;
+ };
+ etsec3_clk: soc-clk@26 {
+ fsl,pmcdr-mask = <0x00000020>;
+ };
+};
--
1.7.3

2013-04-19 10:48:27

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface

From: chenhui zhao <[email protected]>

Some 85xx silicons like MPC8536 and P1022 have a JOG feature, which provides
a dynamic mechanism to lower or raise the CPU core clock at runtime.

This patch adds the support to change CPU frequency using the standard
cpufreq interface. The ratio CORE to CCB can be 1:1(except MPC8536), 3:2,
2:1, 5:2, 3:1, 7:2 and 4:1.

Two CPU cores on P1022 must not in the low power state during the frequency
transition. The driver uses a atomic counter to meet the requirement.

The jog mode frequency transition process on the MPC8536 is similar to
the deep sleep process. The driver need save the CPU state and restore
it after CPU warm reset.

Note:
* The I/O peripherals such as PCIe and eTSEC may lose packets during
the jog mode frequency transition.
* The driver doesn't support MPC8536 Rev 1.0 due to a JOG erratum.
Subsequent revisions of MPC8536 have corrected the erratum.

Signed-off-by: Dave Liu <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Jerry Huang <[email protected]>
Signed-off-by: Zhao Chenhui <[email protected]>
CC: Scott Wood <[email protected]>
---
arch/powerpc/platforms/85xx/Makefile | 1 +
drivers/cpufreq/Kconfig.powerpc | 10 +
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/mpc85xx-cpufreq.c | 390 ++++++++++++++++++++++++++++++++++
4 files changed, 402 insertions(+), 0 deletions(-)
create mode 100644 drivers/cpufreq/mpc85xx-cpufreq.c

diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index a35bab7..da53bde 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_FSL_PMC) += sleep.o
+obj-$(CONFIG_CPU_FREQ_MPC85xx) += sleep.o

obj-y += common.o

diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index e76992f..ba06a00 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -5,3 +5,13 @@ config CPU_FREQ_MAPLE
help
This adds support for frequency switching on Maple 970FX
Evaluation Board and compatible boards (IBM JS2x blades).
+
+config CPU_FREQ_MPC85xx
+ bool "Support for Freescale MPC85xx CPU freq"
+ depends on PPC_85xx && PPC32 && !PPC_E500MC
+ select CPU_FREQ_TABLE
+ help
+ This adds support for dynamic frequency switching on
+ Freescale MPC85xx by cpufreq interface. MPC8536 and P1022
+ have a JOG feature, which provides a dynamic mechanism
+ to lower or raise the CPU core clock at runtime.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 863fd18..e7aecc5 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -61,3 +61,4 @@ obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
##################################################################################
# PowerPC platform drivers
obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
+obj-$(CONFIG_CPU_FREQ_MPC85xx) += mpc85xx-cpufreq.o
diff --git a/drivers/cpufreq/mpc85xx-cpufreq.c b/drivers/cpufreq/mpc85xx-cpufreq.c
new file mode 100644
index 0000000..f56c826
--- /dev/null
+++ b/drivers/cpufreq/mpc85xx-cpufreq.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
+ * Author: Dave Liu <[email protected]>
+ * Modifier: Chenhui Zhao <[email protected]>
+ *
+ * The cpufreq driver is for Freescale 85xx processor,
+ * based on arch/powerpc/platforms/cell/cbe_cpufreq.c
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ * Christian Krafft <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/of_platform.h>
+#include <linux/suspend.h>
+#include <linux/cpu.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+
+#include <asm/prom.h>
+#include <asm/reg.h>
+#include <asm/machdep.h>
+
+#include <sysdev/fsl_soc.h>
+
+static DEFINE_MUTEX(mpc85xx_switch_mutex);
+static void __iomem *guts;
+
+static u32 sysfreq;
+static unsigned int max_pll[2];
+static atomic_t in_jog_process;
+static struct cpufreq_frequency_table *mpc85xx_freqs;
+static int (*set_pll)(unsigned int cpu, unsigned int pll);
+
+static struct cpufreq_frequency_table mpc8536_freqs_table[] = {
+ {3, 0},
+ {4, 0},
+ {5, 0},
+ {6, 0},
+ {7, 0},
+ {8, 0},
+ {0, CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_frequency_table p1022_freqs_table[] = {
+ {2, 0},
+ {3, 0},
+ {4, 0},
+ {5, 0},
+ {6, 0},
+ {7, 0},
+ {8, 0},
+ {0, CPUFREQ_TABLE_END},
+};
+
+#define FREQ_500MHz 500000000
+#define FREQ_800MHz 800000000
+
+#define CORE_RATIO_STRIDE 8
+#define CORE_RATIO_MASK 0x3f
+#define CORE_RATIO_SHIFT 16
+
+#define PORPLLSR 0x0 /* Power-On Reset PLL ratio status register */
+
+#define PMJCR 0x7c /* Power Management Jog Control Register */
+#define PMJCR_CORE0_SPD 0x00001000
+#define PMJCR_CORE_SPD 0x00002000
+
+#define POWMGTCSR 0x80 /* Power management control and status register */
+#define POWMGTCSR_JOG 0x00200000
+#define POWMGTCSR_INT_MASK 0x00000f00
+
+static void spin_while_jogging(void *dummy)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ atomic_inc(&in_jog_process);
+
+ while (atomic_read(&in_jog_process) != 0)
+ barrier();
+
+ local_irq_restore(flags);
+}
+
+static int get_pll(int hw_cpu)
+{
+ int shift;
+ u32 val = in_be32(guts + PORPLLSR);
+
+ shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+
+ return (val >> shift) & CORE_RATIO_MASK;
+}
+
+static int mpc8536_set_pll(unsigned int cpu, unsigned int pll)
+{
+ u32 corefreq, val, mask;
+ unsigned int cur_pll = get_pll(0);
+ unsigned long flags;
+
+ if (pll == cur_pll)
+ return 0;
+
+ val = (pll & CORE_RATIO_MASK) << CORE_RATIO_SHIFT;
+
+ corefreq = sysfreq * pll / 2;
+ /*
+ * Set the COREx_SPD bit if the requested core frequency
+ * is larger than the threshold frequency.
+ */
+ if (corefreq > FREQ_800MHz)
+ val |= PMJCR_CORE_SPD;
+
+ mask = (CORE_RATIO_MASK << CORE_RATIO_SHIFT) | PMJCR_CORE_SPD;
+ clrsetbits_be32(guts + PMJCR, mask, val);
+
+ /* readback to sync write */
+ in_be32(guts + PMJCR);
+
+ local_irq_save(flags);
+ mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_JOG);
+ local_irq_restore(flags);
+
+ /* verify */
+ cur_pll = get_pll(0);
+ if (cur_pll != pll) {
+ pr_err("%s: error. The current PLL is %d instead of %d.\n",
+ __func__, cur_pll, pll);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int p1022_set_pll(unsigned int cpu, unsigned int pll)
+{
+ int index, hw_cpu = get_hard_smp_processor_id(cpu);
+ int shift;
+ u32 corefreq, val, mask = 0;
+ unsigned int cur_pll = get_pll(hw_cpu);
+ unsigned long flags;
+ int ret = 0;
+
+ if (pll == cur_pll)
+ return 0;
+
+ shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+ val = (pll & CORE_RATIO_MASK) << shift;
+
+ corefreq = sysfreq * pll / 2;
+ /*
+ * Set the COREx_SPD bit if the requested core frequency
+ * is larger than the threshold frequency.
+ */
+ if (corefreq > FREQ_500MHz)
+ val |= PMJCR_CORE0_SPD << hw_cpu;
+
+ mask = (CORE_RATIO_MASK << shift) | (PMJCR_CORE0_SPD << hw_cpu);
+ clrsetbits_be32(guts + PMJCR, mask, val);
+
+ /* readback to sync write */
+ in_be32(guts + PMJCR);
+
+ get_online_cpus();
+ /*
+ * A Jog request can not be asserted when any core is in a low
+ * power state on P1022. Before executing a jog request, any
+ * core which is in a low power state must be waked by a
+ * interrupt, and keep waking up until the sequence is
+ * finished.
+ */
+ for_each_present_cpu(index) {
+ if (!cpu_online(index)) {
+ put_online_cpus();
+ pr_err("%s: error, core%d is down.\n", __func__, index);
+ return -1;
+ }
+ }
+
+ atomic_set(&in_jog_process, 0);
+ smp_call_function(spin_while_jogging, NULL, 0);
+
+ local_irq_save(flags);
+
+ /* Wait for the other core to wake. */
+ if (!spin_event_timeout(atomic_read(&in_jog_process) == 1, 1000, 100)) {
+ pr_err("%s: timeout, the other core is not at running state.\n",
+ __func__);
+ ret = -1;
+ goto err;
+ }
+
+ out_be32(guts + POWMGTCSR, POWMGTCSR_JOG | POWMGTCSR_INT_MASK);
+
+ if (!spin_event_timeout(
+ (in_be32(guts + POWMGTCSR) & POWMGTCSR_JOG) == 0, 1000, 100)) {
+ pr_err("%s: timeout, fail to switch the core frequency.\n",
+ __func__);
+ ret = -1;
+ goto err;
+ }
+
+ clrbits32(guts + POWMGTCSR, POWMGTCSR_INT_MASK);
+ in_be32(guts + POWMGTCSR);
+
+ atomic_set(&in_jog_process, 0);
+err:
+ local_irq_restore(flags);
+ put_online_cpus();
+
+ /* verify */
+ cur_pll = get_pll(hw_cpu);
+ if (cur_pll != pll) {
+ pr_err("%s: error, the current PLL of core %d is %d instead of %d.\n",
+ __func__, hw_cpu, cur_pll, pll);
+ return -1;
+ }
+
+ return ret;
+}
+
+/*
+ * cpufreq functions
+ */
+static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ unsigned int i, cur_pll;
+ int hw_cpu = get_hard_smp_processor_id(policy->cpu);
+
+ if (!cpu_present(policy->cpu))
+ return -ENODEV;
+
+ /* the latency of a transition, the unit is ns */
+ policy->cpuinfo.transition_latency = 2000;
+
+ cur_pll = get_pll(hw_cpu);
+
+ /* initialize frequency table */
+ pr_debug("core%d frequency table:\n", hw_cpu);
+ for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
+ if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
+ /* The frequency unit is kHz. */
+ mpc85xx_freqs[i].frequency =
+ (sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
+ } else {
+ mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
+ }
+
+ pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
+
+ if (mpc85xx_freqs[i].index == cur_pll)
+ policy->cur = mpc85xx_freqs[i].frequency;
+ }
+ pr_debug("current pll is at %d, and core freq is%d\n",
+ cur_pll, policy->cur);
+
+ cpufreq_frequency_table_get_attr(mpc85xx_freqs, policy->cpu);
+
+ /*
+ * This ensures that policy->cpuinfo_min
+ * and policy->cpuinfo_max are set correctly.
+ */
+ return cpufreq_frequency_table_cpuinfo(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+
+ return 0;
+}
+
+static int mpc85xx_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ unsigned int new;
+ int ret = 0;
+
+ if (!set_pll)
+ return -ENODEV;
+
+ cpufreq_frequency_table_target(policy,
+ mpc85xx_freqs,
+ target_freq,
+ relation,
+ &new);
+
+ freqs.old = policy->cur;
+ freqs.new = mpc85xx_freqs[new].frequency;
+ freqs.cpu = policy->cpu;
+
+ mutex_lock(&mpc85xx_switch_mutex);
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
+ if (!ret) {
+ pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
+ policy->cpu, mpc85xx_freqs[new].frequency,
+ mpc85xx_freqs[new].index);
+
+ ppc_proc_freq = freqs.new * 1000ul;
+ }
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&mpc85xx_switch_mutex);
+
+ return ret;
+}
+
+static struct cpufreq_driver mpc85xx_cpufreq_driver = {
+ .verify = mpc85xx_cpufreq_verify,
+ .target = mpc85xx_cpufreq_target,
+ .init = mpc85xx_cpufreq_cpu_init,
+ .exit = mpc85xx_cpufreq_cpu_exit,
+ .name = "mpc85xx-JOG",
+ .owner = THIS_MODULE,
+ .flags = CPUFREQ_CONST_LOOPS,
+};
+
+static struct of_device_id mpc85xx_jog_ids[] = {
+ { .compatible = "fsl,mpc8536-guts", },
+ { .compatible = "fsl,p1022-guts", },
+ {}
+};
+
+static int __init mpc85xx_jog_init(void)
+{
+ struct device_node *np;
+ unsigned int svr;
+
+ np = of_find_matching_node(NULL, mpc85xx_jog_ids);
+ if (!np)
+ return -ENODEV;
+
+ guts = of_iomap(np, 0);
+ if (!guts) {
+ of_node_put(np);
+ return -ENODEV;
+ }
+
+ sysfreq = fsl_get_sys_freq();
+
+ if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
+ svr = mfspr(SPRN_SVR);
+ if ((svr & 0x7fff) == 0x10) {
+ pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
+ of_node_put(np);
+ return -ENODEV;
+ }
+ mpc85xx_freqs = mpc8536_freqs_table;
+ set_pll = mpc8536_set_pll;
+ max_pll[0] = get_pll(0);
+
+ } else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
+ mpc85xx_freqs = p1022_freqs_table;
+ set_pll = p1022_set_pll;
+ max_pll[0] = get_pll(0);
+ max_pll[1] = get_pll(1);
+ }
+
+ pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
+
+ of_node_put(np);
+ return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
+}
+
+device_initcall(mpc85xx_jog_init);
--
1.7.3

2013-04-19 10:48:36

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 10/15] powerpc/85xx: fix 64-bit support for cpu hotplug

From: Chen-Hui Zhao <[email protected]>

* The paca[cpu].cpu_start is used as a signal to indicate if the cpu
should start. So it should be cleard in .cpu_die().
* The limit memory routine only needs to be ran once at boot time
by the boot cpu. Prevent other cpus running it again.
* Rearrange the code segment in smp_85xx_kick_cpu() to share codes
between PPC64 and PPC32 as far as possible.

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Andy Fleming <[email protected]>
---
arch/powerpc/Kconfig | 2 +-
arch/powerpc/kernel/smp.c | 3 +++
arch/powerpc/mm/tlb_nohash.c | 6 ++++--
arch/powerpc/platforms/85xx/smp.c | 23 +++++++++++------------
4 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 0ad6e30..aa5794b 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -347,7 +347,7 @@ config SWIOTLB
config HOTPLUG_CPU
bool "Support for enabling/disabling CPUs"
depends on SMP && HOTPLUG && (PPC_PSERIES || \
- PPC_PMAC || PPC_POWERNV || PPC_85xx)
+ PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE)
---help---
Say Y here to be able to disable and re-enable individual
CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 386c7ea..c8aa739 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -401,6 +401,9 @@ void generic_cpu_die(unsigned int cpu)
smp_rmb();
if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
platform_cpu_die(cpu);
+#ifdef CONFIG_PPC64
+ paca[cpu].cpu_start = 0;
+#endif
return;
}
msleep(100);
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index 6888cad..de7bf06 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -627,8 +627,10 @@ static void __early_init_mmu(int boot_cpu)
num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
linear_map_top = map_mem_in_cams(linear_map_top, num_cams);

- /* limit memory so we dont have linear faults */
- memblock_enforce_memory_limit(linear_map_top);
+ if (boot_cpu) {
+ /* limit memory so we dont have linear faults */
+ memblock_enforce_memory_limit(linear_map_top);
+ }

patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
patch_exception(0x1e0, exc_instruction_tlb_miss_bolted_book3e);
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 6eae2e0..74d8cde 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -251,10 +251,6 @@ static int __cpuinit smp_85xx_kick_cpu(int nr)
spin_table = phys_to_virt(*cpu_rel_addr);

local_irq_save(flags);
-#ifdef CONFIG_PPC32
-#ifdef CONFIG_HOTPLUG_CPU
- /* Corresponding to generic_set_cpu_dead() */
- generic_set_cpu_up(nr);

if (system_state == SYSTEM_RUNNING) {
/*
@@ -298,12 +294,19 @@ static int __cpuinit smp_85xx_kick_cpu(int nr)
/* clear the acknowledge status */
__secondary_hold_acknowledge = -1;
}
-#endif
flush_spin_table(spin_table);
out_be32(&spin_table->pir, hw_cpu);
+#ifdef CONFIG_PPC32
out_be32(&spin_table->addr_l, __pa(__early_start));
+#else
+ out_be32(&spin_table->addr_h,
+ __pa(*(u64 *)generic_secondary_smp_init) >> 32);
+ out_be32(&spin_table->addr_l,
+ __pa(*(u64 *)generic_secondary_smp_init) & 0xffffffff);
+#endif
flush_spin_table(spin_table);

+#ifdef CONFIG_PPC32
/* Wait a bit for the CPU to ack. */
if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
10000, 100)) {
@@ -312,18 +315,14 @@ static int __cpuinit smp_85xx_kick_cpu(int nr)
ret = -ENOENT;
goto out;
}
-out:
#else
smp_generic_kick_cpu(nr);
-
- flush_spin_table(spin_table);
- out_be32(&spin_table->pir, hw_cpu);
- out_be64((u64 *)(&spin_table->addr_h),
- __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
- flush_spin_table(spin_table);
#endif
+ /* Corresponding to generic_set_cpu_dead() */
+ generic_set_cpu_up(nr);
cur_booting_core = hw_cpu;

+out:
local_irq_restore(flags);

if (ioremappable)
--
1.7.3

2013-04-19 10:48:55

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 12/15] powerpc/85xx: add time base sync support for e6500

From: Chen-Hui Zhao <[email protected]>

For e6500, two threads in one core share one time base. Just need
to do time base sync on first thread of one core, and skip it on
the other thread.

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Andy Fleming <[email protected]>
---
arch/powerpc/platforms/85xx/smp.c | 52 +++++++++++++++++++++++++++++++-----
1 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 74d8cde..5f3eee3 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -26,6 +26,7 @@
#include <asm/cacheflush.h>
#include <asm/dbell.h>
#include <asm/fsl_guts.h>
+#include <asm/cputhreads.h>

#include <sysdev/fsl_soc.h>
#include <sysdev/mpic.h>
@@ -45,6 +46,7 @@ static u64 timebase;
static int tb_req;
static int tb_valid;
static u32 cur_booting_core;
+static bool rcpmv2;

#ifdef CONFIG_PPC_E500MC
/* get a physical mask of online cores and booting core */
@@ -53,26 +55,40 @@ static inline u32 get_phy_cpu_mask(void)
u32 mask;
int cpu;

- mask = 1 << cur_booting_core;
- for_each_online_cpu(cpu)
- mask |= 1 << get_hard_smp_processor_id(cpu);
+ if (smt_capable()) {
+ /* two threads in one core share one time base */
+ mask = 1 << cpu_core_index_of_thread(cur_booting_core);
+ for_each_online_cpu(cpu)
+ mask |= 1 << cpu_core_index_of_thread(
+ get_hard_smp_processor_id(cpu));
+ } else {
+ mask = 1 << cur_booting_core;
+ for_each_online_cpu(cpu)
+ mask |= 1 << get_hard_smp_processor_id(cpu);
+ }

return mask;
}

static void mpc85xx_timebase_freeze(int freeze)
{
- struct ccsr_rcpm __iomem *rcpm = guts_regs;
+ u32 *addr;
u32 mask = get_phy_cpu_mask();

+ if (rcpmv2)
+ addr = &((struct ccsr_rcpm_v2 *)guts_regs)->pctbenr;
+ else
+ addr = &((struct ccsr_rcpm *)guts_regs)->ctbenr;
+
if (freeze)
- clrbits32(&rcpm->ctbenr, mask);
+ clrbits32(addr, mask);
else
- setbits32(&rcpm->ctbenr, mask);
+ setbits32(addr, mask);

- /* read back to push the previos write */
- in_be32(&rcpm->ctbenr);
+ /* read back to push the previous write */
+ in_be32(addr);
}
+
#else
static void mpc85xx_timebase_freeze(int freeze)
{
@@ -94,6 +110,16 @@ static void mpc85xx_give_timebase(void)
{
unsigned long flags;

+#ifdef CONFIG_PPC_E500MC
+ /*
+ * If the booting thread is not the first thread of the core,
+ * skip time base sync.
+ */
+ if (smt_capable() &&
+ cur_booting_core != cpu_first_thread_sibling(cur_booting_core))
+ return;
+#endif
+
local_irq_save(flags);

while (!tb_req)
@@ -117,6 +143,12 @@ static void mpc85xx_take_timebase(void)
{
unsigned long flags;

+#ifdef CONFIG_PPC_E500MC
+ if (smt_capable() &&
+ cur_booting_core != cpu_first_thread_sibling(cur_booting_core))
+ return;
+#endif
+
local_irq_save(flags);

tb_req = 1;
@@ -457,6 +489,7 @@ static const struct of_device_id mpc85xx_smp_guts_ids[] = {
{ .compatible = "fsl,p1023-guts", },
{ .compatible = "fsl,p2020-guts", },
{ .compatible = "fsl,qoriq-rcpm-1.0", },
+ { .compatible = "fsl,qoriq-rcpm-2.0", },
{},
};

@@ -483,6 +516,9 @@ void __init mpc85xx_smp_init(void)

np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
if (np) {
+ if (of_device_is_compatible(np, "fsl,qoriq-rcpm-2.0"))
+ rcpmv2 = true;
+
guts_regs = of_iomap(np, 0);
of_node_put(np);
if (!guts_regs) {
--
1.7.3

2013-04-19 10:48:40

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 14/15] powerpc/smp: add cpu hotplug support for e6500

From: Chen-Hui Zhao <[email protected]>

* Only if two threads of one core are offline, the core can
enter PH20 state.
* Clear PH20 bits before core reset, or core will not restart.
* Introduced a variable l2cache_type in the struce cpu_spec to
indentify the type of L2 cache.

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Andy Fleming <[email protected]>
---
arch/powerpc/include/asm/cputable.h | 10 ++++++++
arch/powerpc/kernel/cputable.c | 5 ++++
arch/powerpc/platforms/85xx/smp.c | 40 +++++++++++++++++++++++++++++-----
3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index f326444..3715def 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -33,6 +33,13 @@ enum powerpc_pmc_type {
PPC_PMC_G4 = 3,
};

+enum powerpc_l2cache_type {
+ PPC_L2_CACHE_DEFAULT = 0,
+ PPC_L2_CACHE_CORE = 1, /* L2 cache used exclusively by one core */
+ PPC_L2_CACHE_CLUSTER = 2, /* L2 cache shared by a core cluster */
+ PPC_L2_CACHE_SOC = 3, /* L2 cache shared by all cores */
+};
+
struct pt_regs;

extern int machine_check_generic(struct pt_regs *regs);
@@ -58,6 +65,9 @@ struct cpu_spec {
unsigned int icache_bsize;
unsigned int dcache_bsize;

+ /* L2 cache type */
+ enum powerpc_l2cache_type l2cache_type;
+
/* number of performance monitor counters */
unsigned int num_pmcs;
enum powerpc_pmc_type pmc_type;
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index cc39139..a7329c1 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -2004,6 +2004,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_e500v1,
.machine_check = machine_check_e500,
.platform = "ppc8540",
+ .l2cache_type = PPC_L2_CACHE_SOC,
},
{ /* e500v2 */
.pvr_mask = 0xffff0000,
@@ -2023,6 +2024,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_e500v2,
.machine_check = machine_check_e500,
.platform = "ppc8548",
+ .l2cache_type = PPC_L2_CACHE_SOC,
},
{ /* e500mc */
.pvr_mask = 0xffff0000,
@@ -2040,6 +2042,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_e500mc,
.machine_check = machine_check_e500mc,
.platform = "ppce500mc",
+ .l2cache_type = PPC_L2_CACHE_CORE,
},
#endif /* CONFIG_PPC32 */
{ /* e5500 */
@@ -2061,6 +2064,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
#endif
.machine_check = machine_check_e500mc,
.platform = "ppce5500",
+ .l2cache_type = PPC_L2_CACHE_CORE,
},
{ /* e6500 */
.pvr_mask = 0xffff0000,
@@ -2082,6 +2086,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
#endif
.machine_check = machine_check_e500mc,
.platform = "ppce6500",
+ .l2cache_type = PPC_L2_CACHE_CLUSTER,
},
#ifdef CONFIG_PPC32
{ /* default match */
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 5f3eee3..a8b4df7 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -166,13 +166,31 @@ static void core_reset_erratum(int hw_cpu)
{
#ifdef CONFIG_PPC_E500MC
struct ccsr_rcpm __iomem *rcpm = guts_regs;
+ struct ccsr_rcpm_v2 __iomem *rcpm_v2 = guts_regs;

- clrbits32(&rcpm->cnapcr, 1 << hw_cpu);
+ if (rcpmv2)
+ setbits32(&rcpm_v2->pcph20clrr,
+ 1 << cpu_core_index_of_thread(hw_cpu));
+ else
+ clrbits32(&rcpm->cnapcr, 1 << hw_cpu);
#endif
}

#ifdef CONFIG_HOTPLUG_CPU
#ifdef CONFIG_PPC_E500MC
+static inline bool is_core_down(unsigned int thread)
+{
+ cpumask_t thd_mask;
+
+ if (!smt_capable())
+ return true;
+
+ cpumask_shift_left(&thd_mask, &threads_core_mask,
+ cpu_core_index_of_thread(thread) * threads_per_core);
+
+ return !cpumask_intersects(&thd_mask, cpu_online_mask);
+}
+
static void __cpuinit smp_85xx_mach_cpu_die(void)
{
unsigned int cpu = smp_processor_id();
@@ -183,8 +201,11 @@ static void __cpuinit smp_85xx_mach_cpu_die(void)

mtspr(SPRN_TCR, 0);

- __flush_disable_L1();
- disable_backside_L2_cache();
+ if (is_core_down(cpu))
+ __flush_disable_L1();
+
+ if (cur_cpu_spec->l2cache_type == PPC_L2_CACHE_CORE)
+ disable_backside_L2_cache();

generic_set_cpu_dead(cpu);

@@ -195,9 +216,16 @@ void platform_cpu_die(unsigned int cpu)
{
unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
struct ccsr_rcpm __iomem *rcpm = guts_regs;
-
- /* Core Nap Operation */
- setbits32(&rcpm->cnapcr, 1 << hw_cpu);
+ struct ccsr_rcpm_v2 __iomem *rcpm_v2 = guts_regs;
+
+ if (rcpmv2 && is_core_down(cpu)) {
+ /* enter PH20 status */
+ setbits32(&rcpm_v2->pcph20setr,
+ 1 << cpu_core_index_of_thread(hw_cpu));
+ } else if (!rcpmv2) {
+ /* Core Nap Operation */
+ setbits32(&rcpm->cnapcr, 1 << hw_cpu);
+ }
}
#else
/* for e500v1 and e500v2 */
--
1.7.3

2013-04-19 10:48:53

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 15/15] powerpc/rcpm: add sleep support for T4/B4 chips

From: Chen-Hui Zhao <[email protected]>

RCPM unit controls the power managment of T4/B4 chips. Software can
access RCPM registers to put specific thread/core in PH10/PH15/PH20/PH30
state or put the device in LPM10/LPM20/LPM40 mode.

The RCPM unit supports several wake up sources through internal timers
and internal and external interrupts.

When the device enter sleep state, it will be put in LPM20 mode.
The command is "echo standby > /sys/power/state".

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Andy Fleming <[email protected]>
---
arch/powerpc/sysdev/fsl_rcpm.c | 54 +++++++++++++++++++++++++++++++++++++---
1 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c
index fd789da..10e5cb3 100644
--- a/arch/powerpc/sysdev/fsl_rcpm.c
+++ b/arch/powerpc/sysdev/fsl_rcpm.c
@@ -20,6 +20,7 @@
#include <asm/fsl_guts.h>

static struct ccsr_rcpm __iomem *rcpm_regs;
+static struct ccsr_rcpm_v2 __iomem *rcpm2_regs;

static int rcpm_suspend_enter(suspend_state_t state)
{
@@ -53,6 +54,41 @@ static int rcpm_suspend_enter(suspend_state_t state)
return ret;
}

+static int rcpm_v2_suspend_enter(suspend_state_t state)
+{
+ int ret = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+
+ /* clear previous LPM20 status */
+ setbits32(&rcpm2_regs->powmgtcsr, RCPM_POWMGTCSR_P_LPM20_ST);
+ /* enter LPM20 status */
+ setbits32(&rcpm2_regs->powmgtcsr, RCPM_POWMGTCSR_LPM20_RQ);
+
+ /* At this point, the device is in LPM20 status. */
+
+ /* resume ... */
+ ret = spin_event_timeout(
+ (in_be32(&rcpm2_regs->powmgtcsr) & RCPM_POWMGTCSR_LPM20_ST)
+ == 0, 10000, 10);
+ if (!ret) {
+ pr_err("%s: timeout waiting for LPM20 bit to be cleared\n",
+ __func__);
+ ret = -EINVAL;
+ }
+
+ break;
+
+ default:
+ ret = -EINVAL;
+
+ }
+
+ return ret;
+
+}
+
static int rcpm_suspend_valid(suspend_state_t state)
{
if (state == PM_SUSPEND_STANDBY)
@@ -63,16 +99,25 @@ static int rcpm_suspend_valid(suspend_state_t state)

static const struct platform_suspend_ops rcpm_suspend_ops = {
.valid = rcpm_suspend_valid,
- .enter = rcpm_suspend_enter,
};

static int rcpm_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;

- rcpm_regs = of_iomap(np, 0);
- if (!rcpm_regs)
- return -ENOMEM;
+ if (of_device_is_compatible(np, "fsl,qoriq-rcpm-2.0")) {
+ rcpm2_regs = of_iomap(np, 0);
+ if (!rcpm2_regs)
+ return -ENOMEM;
+
+ rcpm_suspend_ops.enter = rcpm_v2_suspend_enter;
+ } else {
+ rcpm_regs = of_iomap(np, 0);
+ if (!rcpm_regs)
+ return -ENOMEM;
+
+ rcpm_suspend_ops.enter = rcpm_suspend_enter;
+ }

suspend_set_ops(&rcpm_suspend_ops);

@@ -82,6 +127,7 @@ static int rcpm_probe(struct platform_device *pdev)

static const struct of_device_id rcpm_ids[] = {
{ .compatible = "fsl,qoriq-rcpm-1.0", },
+ { .compatible = "fsl,qoriq-rcpm-2.0", },
{ },
};

--
1.7.3

2013-04-19 10:48:34

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 09/15] powerpc/rcpm: add sleep feature for SoCs using RCPM

The SoCs which have a RCPM (Run Control/Power Management) module
support power management feature. This patch implements sleep feature.

In sleep mode, the clocks of cores and unused IP blocks will be
turned off. The IP blocks which are allowed to wake up the system
are still running.

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
---
arch/powerpc/Kconfig | 4 +-
arch/powerpc/include/asm/fsl_guts.h | 1 +
arch/powerpc/platforms/85xx/Kconfig | 1 +
arch/powerpc/sysdev/Kconfig | 5 ++
arch/powerpc/sysdev/Makefile | 1 +
arch/powerpc/sysdev/fsl_rcpm.c | 101 +++++++++++++++++++++++++++++++++++
6 files changed, 111 insertions(+), 2 deletions(-)
create mode 100644 arch/powerpc/sysdev/fsl_rcpm.c

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index b6851be..0ad6e30 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -220,7 +220,7 @@ config ARCH_HIBERNATION_POSSIBLE
config ARCH_SUSPEND_POSSIBLE
def_bool y
depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
- (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+ FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \
|| 44x || 40x

config PPC_DCR_NATIVE
@@ -694,7 +694,7 @@ config FSL_PCI
config FSL_PMC
bool
default y
- depends on SUSPEND && (PPC_85xx || PPC_86xx)
+ depends on SUSPEND && ((PPC_85xx && !PPC_E500MC) || PPC_86xx)
help
Freescale MPC85xx/MPC86xx power management controller support
(suspend/resume). For MPC83xx see platforms/83xx/suspend.c
diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index 4eac1cf..b8a08d5 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -124,6 +124,7 @@ struct ccsr_rcpm {
u8 res0038[4];
__be32 cwdtdsr; /* 0x003c - Core watchdog detect status register */
__be32 powmgtcsr; /* 0x0040 - Power Mangement Control & Status Register */
+#define RCPM_POWMGTCSR_SLP 0x00020000
u8 res0044[12];
__be32 ippdexpcr; /* 0x0050 - IP Powerdown Exception Control Register */
u8 res0054[16];
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 8f02b05..c0aa36e 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -8,6 +8,7 @@ menuconfig FSL_SOC_BOOKE
select FSL_PCI if PCI
select SERIAL_8250_EXTENDED if SERIAL_8250
select SERIAL_8250_SHARE_IRQ if SERIAL_8250
+ select FSL_CORENET_RCPM if SUSPEND && PPC_E500MC
default y

if FSL_SOC_BOOKE
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index a84fecf..6c22d91 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -33,3 +33,8 @@ config SCOM_DEBUGFS
config GE_FPGA
bool
default n
+
+config FSL_CORENET_RCPM
+ bool
+ help
+ This option enables support for RCPM (Run Control/Power Management).
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index b0a518e..f12b856 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o fsl_mpic_err.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y)
obj-$(CONFIG_FSL_PMC) += fsl_pmc.o
+obj-$(CONFIG_FSL_CORENET_RCPM) += fsl_rcpm.o
obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c
new file mode 100644
index 0000000..fd789da
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_rcpm.c
@@ -0,0 +1,101 @@
+/*
+ * RCPM(Run Control/Power Management) support
+ *
+ * Copyright 2012-2013 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/suspend.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_platform.h>
+
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+#include <asm/fsl_guts.h>
+
+static struct ccsr_rcpm __iomem *rcpm_regs;
+
+static int rcpm_suspend_enter(suspend_state_t state)
+{
+ int ret = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+
+ flush_dcache_L1();
+ flush_backside_L2_cache();
+
+ setbits32(&rcpm_regs->powmgtcsr, RCPM_POWMGTCSR_SLP);
+
+ /* At this point, the device is in sleep mode. */
+
+ /* Upon resume, wait for SLP bit to be clear. */
+ ret = spin_event_timeout(
+ (in_be32(&rcpm_regs->powmgtcsr) & RCPM_POWMGTCSR_SLP) == 0,
+ 10000, 10);
+ if (!ret) {
+ pr_err("%s: timeout waiting for SLP bit to be cleared\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+
+ }
+ return ret;
+}
+
+static int rcpm_suspend_valid(suspend_state_t state)
+{
+ if (state == PM_SUSPEND_STANDBY)
+ return 1;
+ else
+ return 0;
+}
+
+static const struct platform_suspend_ops rcpm_suspend_ops = {
+ .valid = rcpm_suspend_valid,
+ .enter = rcpm_suspend_enter,
+};
+
+static int rcpm_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+
+ rcpm_regs = of_iomap(np, 0);
+ if (!rcpm_regs)
+ return -ENOMEM;
+
+ suspend_set_ops(&rcpm_suspend_ops);
+
+ dev_info(&pdev->dev, "Freescale RCPM driver\n");
+ return 0;
+}
+
+static const struct of_device_id rcpm_ids[] = {
+ { .compatible = "fsl,qoriq-rcpm-1.0", },
+ { },
+};
+
+static struct platform_driver rcpm_driver = {
+ .driver = {
+ .name = "fsl-rcpm",
+ .of_match_table = rcpm_ids,
+ },
+ .probe = rcpm_probe,
+};
+
+static int __init rcpm_init(void)
+{
+ return platform_driver_register(&rcpm_driver);
+}
+
+device_initcall(rcpm_init);
--
1.7.3

2013-04-19 10:48:32

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 11/15] powerpc/rcpm: add struct ccsr_rcpm_v2

From: Chen-Hui Zhao <[email protected]>

Add struct ccsr_rcpm_v2 to descibe the v2 RCPM register map on some SoCs,
such as T4240, etc.

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Andy Fleming <[email protected]>
---
arch/powerpc/include/asm/fsl_guts.h | 66 +++++++++++++++++++++++++++++++++++
1 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index b8a08d5..193d1f1 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -145,6 +145,72 @@ struct ccsr_rcpm {
__be32 cmcpmaskcr; /* 0x00a4 - Core machine check mask control register */
};

+struct ccsr_rcpm_v2 {
+ u8 res_00[12];
+ u32 tph10sr0; /* Thread PH10 Status Register */
+ u8 res_10[12];
+ u32 tph10setr0; /* Thread PH10 Set Control Register */
+ u8 res_20[12];
+ u32 tph10clrr0; /* Thread PH10 Clear Control Register */
+ u8 res_30[12];
+ u32 tph10psr0; /* Thread PH10 Previous Status Register */
+ u8 res_40[12];
+ u32 twaitsr0; /* Thread Wait Status Register */
+ u8 res_50[96];
+ u32 pcph15sr; /* Physical Core PH15 Status Register */
+ u32 pcph15setr; /* Physical Core PH15 Set Control Register */
+ u32 pcph15clrr; /* Physical Core PH15 Clear Control Register */
+ u32 pcph15psr; /* Physical Core PH15 Prev Status Register */
+ u8 res_c0[16];
+ u32 pcph20sr; /* Physical Core PH20 Status Register */
+ u32 pcph20setr; /* Physical Core PH20 Set Control Register */
+ u32 pcph20clrr; /* Physical Core PH20 Clear Control Register */
+ u32 pcph20psr; /* Physical Core PH20 Prev Status Register */
+ u32 pcpw20sr; /* Physical Core PW20 Status Register */
+ u8 res_e0[12];
+ u32 pcph30sr; /* Physical Core PH30 Status Register */
+ u32 pcph30setr; /* Physical Core PH30 Set Control Register */
+ u32 pcph30clrr; /* Physical Core PH30 Clear Control Register */
+ u32 pcph30psr; /* Physical Core PH30 Prev Status Register */
+ u8 res_100[32];
+ u32 ippwrgatecr; /* IP Power Gating Control Register */
+ u8 res_124[12];
+ u32 powmgtcsr; /* Power Management Control & Status Reg */
+#define RCPM_POWMGTCSR_LPM20_RQ 0x00100000
+#define RCPM_POWMGTCSR_LPM20_ST 0x00000200
+#define RCPM_POWMGTCSR_P_LPM20_ST 0x00000100
+ u8 res_134[12];
+ u32 ippdexpcr[4]; /* IP Powerdown Exception Control Reg */
+ u8 res_150[12];
+ u32 tpmimr0; /* Thread PM Interrupt Mask Reg */
+ u8 res_160[12];
+ u32 tpmcimr0; /* Thread PM Crit Interrupt Mask Reg */
+ u8 res_170[12];
+ u32 tpmmcmr0; /* Thread PM Machine Check Interrupt Mask Reg */
+ u8 res_180[12];
+ u32 tpmnmimr0; /* Thread PM NMI Mask Reg */
+ u8 res_190[12];
+ u32 tmcpmaskcr0; /* Thread Machine Check Mask Control Reg */
+ u32 pctbenr; /* Physical Core Time Base Enable Reg */
+ u32 pctbclkselr; /* Physical Core Time Base Clock Select */
+ u32 tbclkdivr; /* Time Base Clock Divider Register */
+ u8 res_1ac[4];
+ u32 ttbhltcr[4]; /* Thread Time Base Halt Control Register */
+ u32 clpcl10sr; /* Cluster PCL10 Status Register */
+ u32 clpcl10setr; /* Cluster PCL30 Set Control Register */
+ u32 clpcl10clrr; /* Cluster PCL30 Clear Control Register */
+ u32 clpcl10psr; /* Cluster PCL30 Prev Status Register */
+ u32 cddslpsetr; /* Core Domain Deep Sleep Set Register */
+ u32 cddslpclrr; /* Core Domain Deep Sleep Clear Register */
+ u32 cdpwroksetr; /* Core Domain Power OK Set Register */
+ u32 cdpwrokclrr; /* Core Domain Power OK Clear Register */
+ u32 cdpwrensr; /* Core Domain Power Enable Status Register */
+ u32 cddslsr; /* Core Domain Deep Sleep Status Register */
+ u8 res_1e8[8];
+ u32 dslpcntcr[8]; /* Deep Sleep Counter Cfg Register */
+ u8 res_300[3568];
+};
+
#ifdef CONFIG_PPC_86xx

#define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */
--
1.7.3

2013-04-19 10:49:47

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 13/15] powerpc/85xx: add support for e6500 L1 cache operation

From: Chen-Hui Zhao <[email protected]>

The L1 Data Cache of e6500 contains no modified data, no flush
is required.

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Andy Fleming <[email protected]>
---
arch/powerpc/kernel/fsl_booke_cache.S | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/fsl_booke_cache.S b/arch/powerpc/kernel/fsl_booke_cache.S
index 232c47b..24a52bb 100644
--- a/arch/powerpc/kernel/fsl_booke_cache.S
+++ b/arch/powerpc/kernel/fsl_booke_cache.S
@@ -65,13 +65,22 @@ _GLOBAL(flush_dcache_L1)

blr

+#define PVR_E6500 0x8040
+
/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
_GLOBAL(__flush_disable_L1)
+/* L1 Data Cache of e6500 contains no modified data, no flush is required */
+ mfspr r3, SPRN_PVR
+ rlwinm r4, r3, 16, 0xffff
+ lis r5, 0
+ ori r5, r5, PVR_E6500@l
+ cmpw r4, r5
+ beq 2f
mflr r10
bl flush_dcache_L1 /* Flush L1 d-cache */
mtlr r10

- msync
+2: msync
mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
li r5, 2
rlwimi r4, r5, 0, 3
--
1.7.3

2013-04-19 10:50:21

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 07/15] powerpc/85xx: add time base sync for SoCs based on e500mc/e5500

From: Chen-Hui Zhao <[email protected]>

In the case of SMP, during the time base sync period, all time bases of
online cores must stop, then start simultaneously.

There is a RCPM (Run Control/Power Management) module in CoreNet based SoCs.
Define a struct ccsr_rcpm to describe the register map.

This patch supports SoCs based on e500mc/e5500, such as P4080, P5020,
etc.

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
---
arch/powerpc/include/asm/fsl_guts.h | 38 +++++++++++++++++++++++++++++++++++
arch/powerpc/platforms/85xx/smp.c | 32 +++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index 77ced0b..4eac1cf 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -106,6 +106,44 @@ struct ccsr_guts {
/* Alternate function signal multiplex control */
#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))

+struct ccsr_rcpm {
+ u8 res0000[4];
+ __be32 cdozsr; /* 0x0004 - Core Doze Status Register */
+ u8 res0008[4];
+ __be32 cdozcr; /* 0x000c - Core Doze Control Register */
+ u8 res0010[4];
+ __be32 cnapsr; /* 0x0014 - Core Nap Status Register */
+ u8 res0018[4];
+ __be32 cnapcr; /* 0x001c - Core Nap Control Register */
+ u8 res0020[4];
+ __be32 cdozpsr; /* 0x0024 - Core Doze Previous Status Register */
+ u8 res0028[4];
+ __be32 cnappsr; /* 0x002c - Core Nap Previous Status Register */
+ u8 res0030[4];
+ __be32 cwaitsr; /* 0x0034 - Core Wait Status Register */
+ u8 res0038[4];
+ __be32 cwdtdsr; /* 0x003c - Core watchdog detect status register */
+ __be32 powmgtcsr; /* 0x0040 - Power Mangement Control & Status Register */
+ u8 res0044[12];
+ __be32 ippdexpcr; /* 0x0050 - IP Powerdown Exception Control Register */
+ u8 res0054[16];
+ __be32 cpmimr; /* 0x0064 - Core PM IRQ Mask Register */
+ u8 res0068[4];
+ __be32 cpmcimr; /* 0x006c - Core PM Critical IRQ Mask Register */
+ u8 res0070[4];
+ __be32 cpmmcmr; /* 0x0074 - Core PM Machine Check Mask Register */
+ u8 res0078[4];
+ __be32 cpmnmimr; /* 0x007c - Core PM NMI Mask Register */
+ u8 res0080[4];
+ __be32 ctbenr; /* 0x0084 - Core Time Base Enable Register */
+ u8 res0088[4];
+ __be32 ctbckselr; /* 0x008c - Core Time Base Clock Select Register */
+ u8 res0090[4];
+ __be32 ctbhltcr; /* 0x0094 - Core Time Base Halt Control Register */
+ u8 res0098[4];
+ __be32 cmcpmaskcr; /* 0x00a4 - Core machine check mask control register */
+};
+
#ifdef CONFIG_PPC_86xx

#define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 6a17599..6c2fe6b 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -44,7 +44,36 @@ static struct ccsr_guts __iomem *guts;
static u64 timebase;
static int tb_req;
static int tb_valid;
+static u32 cur_booting_core;

+#ifdef CONFIG_PPC_E500MC
+/* get a physical mask of online cores and booting core */
+static inline u32 get_phy_cpu_mask(void)
+{
+ u32 mask;
+ int cpu;
+
+ mask = 1 << cur_booting_core;
+ for_each_online_cpu(cpu)
+ mask |= 1 << get_hard_smp_processor_id(cpu);
+
+ return mask;
+}
+
+static void mpc85xx_timebase_freeze(int freeze)
+{
+ struct ccsr_rcpm __iomem *rcpm = (typeof(rcpm))guts;
+ u32 mask = get_phy_cpu_mask();
+
+ if (freeze)
+ clrbits32(&rcpm->ctbenr, mask);
+ else
+ setbits32(&rcpm->ctbenr, mask);
+
+ /* read back to push the previos write */
+ in_be32(&rcpm->ctbenr);
+}
+#else
static void mpc85xx_timebase_freeze(int freeze)
{
uint32_t mask;
@@ -57,6 +86,7 @@ static void mpc85xx_timebase_freeze(int freeze)

in_be32(&guts->devdisr);
}
+#endif

static void mpc85xx_give_timebase(void)
{
@@ -244,6 +274,7 @@ out:
__pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
flush_spin_table(spin_table);
#endif
+ cur_booting_core = hw_cpu;

local_irq_restore(flags);

@@ -378,6 +409,7 @@ static const struct of_device_id mpc85xx_smp_guts_ids[] = {
{ .compatible = "fsl,p1022-guts", },
{ .compatible = "fsl,p1023-guts", },
{ .compatible = "fsl,p2020-guts", },
+ { .compatible = "fsl,qoriq-rcpm-1.0", },
{},
};

--
1.7.3

2013-04-19 10:50:42

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 08/15] powerpc/85xx: add cpu hotplug support for e500mc/e5500

From: Chen-Hui Zhao <[email protected]>

Add support to disable and re-enable individual cores at runtime.
This supports e500mc/e5500 core based SoCs.

To prevent the register access race, only read/write RCPM registers
in platform_cpu_die() on the boot cpu instead of accessing by individual
cpus. Platform implementations can override the platform_cpu_die().

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Andy Fleming <[email protected]>
---
arch/powerpc/Kconfig | 2 +-
arch/powerpc/include/asm/smp.h | 1 +
arch/powerpc/kernel/smp.c | 16 ++++++++++-
arch/powerpc/platforms/85xx/smp.c | 56 ++++++++++++++++++++++++++++++++++--
4 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 0e11a09..b6851be 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -347,7 +347,7 @@ config SWIOTLB
config HOTPLUG_CPU
bool "Support for enabling/disabling CPUs"
depends on SMP && HOTPLUG && (PPC_PSERIES || \
- PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
+ PPC_PMAC || PPC_POWERNV || PPC_85xx)
---help---
Say Y here to be able to disable and re-enable individual
CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 195ce2a..95be584 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -60,6 +60,7 @@ extern void smp_generic_take_timebase(void);
DECLARE_PER_CPU(unsigned int, cpu_pvr);

#ifdef CONFIG_HOTPLUG_CPU
+void platform_cpu_die(unsigned int cpu);
extern void migrate_irqs(void);
int generic_cpu_disable(void);
void generic_cpu_die(unsigned int cpu);
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 76bd9da..386c7ea 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -381,14 +381,28 @@ int generic_cpu_disable(void)
return 0;
}

+/**
+ * platform_cpu_die() - do platform related operations on the boot cpu
+ * after CPU_DEAD is assigned to the variable cpu_state of the dying cpu.
+ * Platform implementations can override this.
+ *
+ * @cpu: the cpu to die
+ */
+void __attribute__ ((weak)) platform_cpu_die(unsigned int cpu)
+{
+ return;
+}
+
void generic_cpu_die(unsigned int cpu)
{
int i;

for (i = 0; i < 100; i++) {
smp_rmb();
- if (per_cpu(cpu_state, cpu) == CPU_DEAD)
+ if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+ platform_cpu_die(cpu);
return;
+ }
msleep(100);
}
printk(KERN_ERR "CPU%d didn't die...\n", cpu);
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 6c2fe6b..6eae2e0 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -40,7 +40,7 @@ struct epapr_spin_table {
u32 pir;
};

-static struct ccsr_guts __iomem *guts;
+static void __iomem *guts_regs;
static u64 timebase;
static int tb_req;
static int tb_valid;
@@ -62,7 +62,7 @@ static inline u32 get_phy_cpu_mask(void)

static void mpc85xx_timebase_freeze(int freeze)
{
- struct ccsr_rcpm __iomem *rcpm = (typeof(rcpm))guts;
+ struct ccsr_rcpm __iomem *rcpm = guts_regs;
u32 mask = get_phy_cpu_mask();

if (freeze)
@@ -76,6 +76,7 @@ static void mpc85xx_timebase_freeze(int freeze)
#else
static void mpc85xx_timebase_freeze(int freeze)
{
+ struct ccsr_guts __iomem *guts = guts_regs;
uint32_t mask;

mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
@@ -84,6 +85,7 @@ static void mpc85xx_timebase_freeze(int freeze)
else
clrbits32(&guts->devdisr, mask);

+ /* read back to push the previous write */
in_be32(&guts->devdisr);
}
#endif
@@ -128,7 +130,45 @@ static void mpc85xx_take_timebase(void)
local_irq_restore(flags);
}

+static void core_reset_erratum(int hw_cpu)
+{
+#ifdef CONFIG_PPC_E500MC
+ struct ccsr_rcpm __iomem *rcpm = guts_regs;
+
+ clrbits32(&rcpm->cnapcr, 1 << hw_cpu);
+#endif
+}
+
#ifdef CONFIG_HOTPLUG_CPU
+#ifdef CONFIG_PPC_E500MC
+static void __cpuinit smp_85xx_mach_cpu_die(void)
+{
+ unsigned int cpu = smp_processor_id();
+
+ local_irq_disable();
+ idle_task_exit();
+ mb();
+
+ mtspr(SPRN_TCR, 0);
+
+ __flush_disable_L1();
+ disable_backside_L2_cache();
+
+ generic_set_cpu_dead(cpu);
+
+ while (1);
+}
+
+void platform_cpu_die(unsigned int cpu)
+{
+ unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
+ struct ccsr_rcpm __iomem *rcpm = guts_regs;
+
+ /* Core Nap Operation */
+ setbits32(&rcpm->cnapcr, 1 << hw_cpu);
+}
+#else
+/* for e500v1 and e500v2 */
static void __cpuinit smp_85xx_mach_cpu_die(void)
{
unsigned int cpu = smp_processor_id();
@@ -156,6 +196,7 @@ static void __cpuinit smp_85xx_mach_cpu_die(void)
while (1)
;
}
+#endif /* CONFIG_PPC_E500MC */
#endif

static inline void flush_spin_table(void *spin_table)
@@ -228,6 +269,13 @@ static int __cpuinit smp_85xx_kick_cpu(int nr)
flush_spin_table(spin_table);

/*
+ * Due to an erratum that core hard reset and core warm reset
+ * are unable to wake up cores from power management modes,
+ * wake up cores before reset.
+ */
+ core_reset_erratum(hw_cpu);
+
+ /*
* We don't set the BPTR register here since it already points
* to the boot page properly.
*/
@@ -436,9 +484,9 @@ void __init mpc85xx_smp_init(void)

np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
if (np) {
- guts = of_iomap(np, 0);
+ guts_regs = of_iomap(np, 0);
of_node_put(np);
- if (!guts) {
+ if (!guts_regs) {
pr_err("%s: Could not map guts node address\n",
__func__);
return;
--
1.7.3

2013-04-19 10:51:06

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 05/15] fsl_pmc: update device bindings

From: Li Yang <[email protected]>

Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Zhao Chenhui <[email protected]>
---
.../devicetree/bindings/powerpc/fsl/pmc.txt | 59 +++++++++++--------
1 files changed, 34 insertions(+), 25 deletions(-)

diff --git a/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt b/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
index 07256b7..f1f749f 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
@@ -9,15 +9,20 @@ Properties:

"fsl,mpc8548-pmc" should be listed for any chip whose PMC is
compatible. "fsl,mpc8536-pmc" should also be listed for any chip
- whose PMC is compatible, and implies deep-sleep capability.
+ whose PMC is compatible, and implies deep-sleep capability and
+ wake on user defined packet(wakeup on ARP).
+
+ "fsl,p1022-pmc" should be listed for any chip whose PMC is
+ compatible, and implies lossless Ethernet capability during sleep.

"fsl,mpc8641d-pmc" should be listed for any chip whose PMC is
compatible; all statements below that apply to "fsl,mpc8548-pmc" also
apply to "fsl,mpc8641d-pmc".

Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these
- bit assignments are indicated via the sleep specifier in each device's
- sleep property.
+ bit assignments are indicated via the clock nodes. Device which has a
+ controllable clock source should have a "fsl,pmc-handle" property pointing
+ to the clock node.

- reg: For devices compatible with "fsl,mpc8349-pmc", the first resource
is the PMC block, and the second resource is the Clock Configuration
@@ -33,31 +38,35 @@ Properties:
this is a phandle to an "fsl,gtm" node on which timer 4 can be used as
a wakeup source from deep sleep.

-Sleep specifiers:
+Clock nodes:
+The clock nodes are to describe the masks in PM controller registers for each
+soc clock.
+- fsl,pmcdr-mask: For "fsl,mpc8548-pmc"-compatible devices, the mask will be
+ ORed into PMCDR before suspend if the device using this clock is the wake-up
+ source and need to be running during low power mode; clear the mask if
+ otherwise.

- fsl,mpc8349-pmc: Sleep specifiers consist of one cell. For each bit
- that is set in the cell, the corresponding bit in SCCR will be saved
- and cleared on suspend, and restored on resume. This sleep controller
- supports disabling and resuming devices at any time.
+- fsl,sccr-mask: For "fsl,mpc8349-pmc"-compatible devices, the corresponding
+ bit specified by the mask in SCCR will be saved and cleared on suspend, and
+ restored on resume.

- fsl,mpc8536-pmc: Sleep specifiers consist of three cells, the third of
- which will be ORed into PMCDR upon suspend, and cleared from PMCDR
- upon resume. The first two cells are as described for fsl,mpc8578-pmc.
- This sleep controller only supports disabling devices during system
- sleep, or permanently.
-
- fsl,mpc8548-pmc: Sleep specifiers consist of one or two cells, the
- first of which will be ORed into DEVDISR (and the second into
- DEVDISR2, if present -- this cell should be zero or absent if the
- hardware does not have DEVDISR2) upon a request for permanent device
- disabling. This sleep controller does not support configuring devices
- to disable during system sleep (unless supported by another compatible
- match), or dynamically.
+- fsl,devdisr-mask: Contain one or two cells, depending on the availability of
+ DEVDISR2 register. For compatible devices, the mask will be ORed into DEVDISR
+ or DEVDISR2 when the clock should be permenently disabled.

Example:

- power@b00 {
- compatible = "fsl,mpc8313-pmc", "fsl,mpc8349-pmc";
- reg = <0xb00 0x100 0xa00 0x100>;
- interrupts = <80 8>;
+ power@e0070 {
+ compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
+ reg = <0xe0070 0x20>;
+
+ etsec1_clk: soc-clk@24 {
+ fsl,pmcdr-mask = <0x00000080>;
+ };
+ etsec2_clk: soc-clk@25 {
+ fsl,pmcdr-mask = <0x00000040>;
+ };
+ etsec3_clk: soc-clk@26 {
+ fsl,pmcdr-mask = <0x00000020>;
+ };
};
--
1.7.3

2013-04-19 10:51:31

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 02/15] powerpc/85xx: add sleep and deep sleep support

Some Freescale SoCs like MPC8536 and P1022 has the deep sleep mode
in addtion to the sleep mode.

In sleep PM mode, the clocks of e500 core and unused IP blocks is
turned off. IP blocks which are allowed to wake up the processor
are still running.

While in deep sleep PM mode, additionally, the power supply is
removed from e500 core and most IP blocks. Only the blocks needed
to wake up the chip out of deep sleep are ON.

This patch supports 32-bit and 36-bit address space.

The sleep mode is equal to the Standby state in Linux. The deep sleep
mode is equal to the Suspend-to-RAM state of Linux Power Management.

Command to enter sleep mode.
echo standby > /sys/power/state
Command to enter deep sleep mode.
echo mem > /sys/power/state

Signed-off-by: Zhao Chenhui <[email protected]>
Signed-off-by: Li Yang <[email protected]>
---
arch/powerpc/platforms/85xx/Makefile | 1 +
arch/powerpc/platforms/85xx/sleep.S | 621 ++++++++++++++++++++++++++++++++++
arch/powerpc/sysdev/fsl_pmc.c | 98 +++++-
arch/powerpc/sysdev/fsl_soc.h | 5 +
4 files changed, 707 insertions(+), 18 deletions(-)
create mode 100644 arch/powerpc/platforms/85xx/sleep.S

diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 2eab37e..a35bab7 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -2,6 +2,7 @@
# Makefile for the PowerPC 85xx linux kernel.
#
obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_FSL_PMC) += sleep.o

obj-y += common.o

diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
new file mode 100644
index 0000000..5a43adb
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep.S
@@ -0,0 +1,621 @@
+/*
+ * Enter and leave deep sleep/sleep state on MPC85xx
+ *
+ * Author: Scott Wood <[email protected]>
+ *
+ * Copyright (C) 2006-2013 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+#include <asm/mmu.h>
+
+#define CCSR_ADDR 0xf0000000
+
+#define L2C_OFFSET 0x20000 /* L2 Cache Controller offset */
+
+#define BPTR_OFFSET 0x20 /* Boot Page Translation Register */
+#define BPTR_EN 0x80000000
+
+#define PMRCCR_OFFSET 0xe0084
+#define PMRCCR_VRCNT_PRE_MASK 0x1f000000
+#define PMRCCR_VRCNT_MASK 0x00ff0000
+
+#define POWMGTSCR_OFFSET 0xe0080
+#define POWMGTSCR_DPSLP 0x00100000 /* deep sleep mode */
+
+#define SS_TB 0x00
+#define SS_HID 0x08 /* 2 HIDs */
+#define SS_IAC 0x10 /* 2 IACs */
+#define SS_DAC 0x18 /* 2 DACs */
+#define SS_DBCR 0x20 /* 3 DBCRs */
+#define SS_PID 0x2c /* 3 PIDs */
+#define SS_SPRG 0x38 /* 8 SPRGs */
+#define SS_IVOR 0x58 /* 20 interrupt vectors */
+#define SS_TCR 0xa8
+#define SS_BUCSR 0xac
+#define SS_L1CSR 0xb0 /* 2 L1CSRs */
+#define SS_MSR 0xb8
+#define SS_USPRG 0xbc
+#define SS_GPREG 0xc0 /* r12-r31 */
+#define SS_LR 0x110
+#define SS_CR 0x114
+#define SS_SP 0x118
+#define SS_CURRENT 0x11c
+#define SS_IVPR 0x120
+#define SS_BPTR 0x124
+
+#define STATE_SAVE_SIZE 0x128
+
+ .section .data
+ .align 5
+mpc85xx_sleep_save_area:
+ .space STATE_SAVE_SIZE
+ccsrbase_low:
+ .long 0
+ccsrbase_high:
+ .long 0
+powmgtreq:
+ .long 0
+
+ .section .text
+ .align 12
+
+ /*
+ * r3 = high word of physical address of CCSR
+ * r4 = low word of physical address of CCSR
+ * r5 = JOG or deep sleep request
+ * JOG-0x00200000, deep sleep-0x00100000
+ */
+_GLOBAL(mpc85xx_enter_deep_sleep)
+ lis r6, ccsrbase_low@ha
+ stw r4, ccsrbase_low@l(r6)
+ lis r6, ccsrbase_high@ha
+ stw r3, ccsrbase_high@l(r6)
+
+ lis r6, powmgtreq@ha
+ stw r5, powmgtreq@l(r6)
+
+ lis r10, mpc85xx_sleep_save_area@h
+ ori r10, r10, mpc85xx_sleep_save_area@l
+
+ mfspr r5, SPRN_HID0
+ mfspr r6, SPRN_HID1
+
+ stw r5, SS_HID+0(r10)
+ stw r6, SS_HID+4(r10)
+
+ mfspr r4, SPRN_IAC1
+ mfspr r5, SPRN_IAC2
+ mfspr r6, SPRN_DAC1
+ mfspr r7, SPRN_DAC2
+
+ stw r4, SS_IAC+0(r10)
+ stw r5, SS_IAC+4(r10)
+ stw r6, SS_DAC+0(r10)
+ stw r7, SS_DAC+4(r10)
+
+ mfspr r4, SPRN_DBCR0
+ mfspr r5, SPRN_DBCR1
+ mfspr r6, SPRN_DBCR2
+
+ stw r4, SS_DBCR+0(r10)
+ stw r5, SS_DBCR+4(r10)
+ stw r6, SS_DBCR+8(r10)
+
+ mfspr r4, SPRN_PID0
+ mfspr r5, SPRN_PID1
+ mfspr r6, SPRN_PID2
+
+ stw r4, SS_PID+0(r10)
+ stw r5, SS_PID+4(r10)
+ stw r6, SS_PID+8(r10)
+
+ mfspr r4, SPRN_SPRG0
+ mfspr r5, SPRN_SPRG1
+ mfspr r6, SPRN_SPRG2
+ mfspr r7, SPRN_SPRG3
+
+ stw r4, SS_SPRG+0x00(r10)
+ stw r5, SS_SPRG+0x04(r10)
+ stw r6, SS_SPRG+0x08(r10)
+ stw r7, SS_SPRG+0x0c(r10)
+
+ mfspr r4, SPRN_SPRG4
+ mfspr r5, SPRN_SPRG5
+ mfspr r6, SPRN_SPRG6
+ mfspr r7, SPRN_SPRG7
+
+ stw r4, SS_SPRG+0x10(r10)
+ stw r5, SS_SPRG+0x14(r10)
+ stw r6, SS_SPRG+0x18(r10)
+ stw r7, SS_SPRG+0x1c(r10)
+
+ mfspr r4, SPRN_IVPR
+ stw r4, SS_IVPR(r10)
+
+ mfspr r4, SPRN_IVOR0
+ mfspr r5, SPRN_IVOR1
+ mfspr r6, SPRN_IVOR2
+ mfspr r7, SPRN_IVOR3
+
+ stw r4, SS_IVOR+0x00(r10)
+ stw r5, SS_IVOR+0x04(r10)
+ stw r6, SS_IVOR+0x08(r10)
+ stw r7, SS_IVOR+0x0c(r10)
+
+ mfspr r4, SPRN_IVOR4
+ mfspr r5, SPRN_IVOR5
+ mfspr r6, SPRN_IVOR6
+ mfspr r7, SPRN_IVOR7
+
+ stw r4, SS_IVOR+0x10(r10)
+ stw r5, SS_IVOR+0x14(r10)
+ stw r6, SS_IVOR+0x18(r10)
+ stw r7, SS_IVOR+0x1c(r10)
+
+ mfspr r4, SPRN_IVOR8
+ mfspr r5, SPRN_IVOR9
+ mfspr r6, SPRN_IVOR10
+ mfspr r7, SPRN_IVOR11
+
+ stw r4, SS_IVOR+0x20(r10)
+ stw r5, SS_IVOR+0x24(r10)
+ stw r6, SS_IVOR+0x28(r10)
+ stw r7, SS_IVOR+0x2c(r10)
+
+ mfspr r4, SPRN_IVOR12
+ mfspr r5, SPRN_IVOR13
+ mfspr r6, SPRN_IVOR14
+ mfspr r7, SPRN_IVOR15
+
+ stw r4, SS_IVOR+0x30(r10)
+ stw r5, SS_IVOR+0x34(r10)
+ stw r6, SS_IVOR+0x38(r10)
+ stw r7, SS_IVOR+0x3c(r10)
+
+ mfspr r4, SPRN_IVOR32
+ mfspr r5, SPRN_IVOR33
+ mfspr r6, SPRN_IVOR34
+ mfspr r7, SPRN_IVOR35
+
+ stw r4, SS_IVOR+0x40(r10)
+ stw r5, SS_IVOR+0x44(r10)
+ stw r6, SS_IVOR+0x48(r10)
+ stw r7, SS_IVOR+0x4c(r10)
+
+ mfspr r4, SPRN_TCR
+ mfspr r5, SPRN_BUCSR
+ mfspr r6, SPRN_L1CSR0
+ mfspr r7, SPRN_L1CSR1
+ mfspr r8, SPRN_USPRG0
+
+ stw r4, SS_TCR(r10)
+ stw r5, SS_BUCSR(r10)
+ stw r6, SS_L1CSR+0(r10)
+ stw r7, SS_L1CSR+4(r10)
+ stw r8, SS_USPRG+0(r10)
+
+ stmw r12, SS_GPREG(r10)
+
+ mfmsr r4
+ mflr r5
+ mfcr r6
+
+ stw r4, SS_MSR(r10)
+ stw r5, SS_LR(r10)
+ stw r6, SS_CR(r10)
+ stw r1, SS_SP(r10)
+ stw r2, SS_CURRENT(r10)
+
+1: mftbu r4
+ mftb r5
+ mftbu r6
+ cmpw r4, r6
+ bne 1b
+
+ stw r4, SS_TB+0(r10)
+ stw r5, SS_TB+4(r10)
+
+ lis r5, ccsrbase_low@ha
+ lwz r4, ccsrbase_low@l(r5)
+ lis r5, ccsrbase_high@ha
+ lwz r3, ccsrbase_high@l(r5)
+
+ /* Disable machine checks and critical exceptions */
+ mfmsr r5
+ rlwinm r5, r5, 0, ~MSR_CE
+ rlwinm r5, r5, 0, ~MSR_ME
+ mtmsr r5
+ isync
+
+ /* Use TLB1[15] to map the CCSR at 0xf0000000 */
+ LOAD_REG_IMMEDIATE(r5, MAS0_TLBSEL(1) | MAS0_ESEL(15))
+ mtspr SPRN_MAS0, r5
+ LOAD_REG_IMMEDIATE(r5,
+ MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(BOOK3E_PAGESZ_1M))
+ mtspr SPRN_MAS1, r5
+ LOAD_REG_IMMEDIATE(r5, CCSR_ADDR | MAS2_I | MAS2_M)
+ mtspr SPRN_MAS2, r5
+ rlwinm r5, r4, 0, MAS3_RPN
+ ori r5, r5, (MAS3_SW | MAS3_SR)
+ mtspr SPRN_MAS3, r5
+ mtspr SPRN_MAS7, r3
+ isync
+ tlbwe
+ isync
+
+ LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + BPTR_OFFSET)
+ lwz r4, 0(r3)
+ stw r4, SS_BPTR(r10)
+
+ LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + L2C_OFFSET)
+ bl flush_disable_L2
+ bl __flush_disable_L1
+
+ /* Enable I-cache, so as not to upset the bus
+ * with our loop.
+ */
+ mfspr r4, SPRN_L1CSR1
+ ori r4, r4, L1CSR1_ICE
+ mtspr SPRN_L1CSR1, r4
+ isync
+
+ /* Set boot page translation */
+ LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + BPTR_OFFSET)
+ lis r4, (mpc85xx_deep_resume - PAGE_OFFSET)@h
+ ori r4, r4, (mpc85xx_deep_resume - PAGE_OFFSET)@l
+ rlwinm r4, r4, 20, 12, 31
+ oris r4, r4, BPTR_EN@h
+ stw r4, 0(r3)
+ lwz r4, 0(r3) /* read-back to flush write */
+ twi 0, r4, 0
+ isync
+
+ /* Disable the decrementer */
+ mfspr r4, SPRN_TCR
+ rlwinm r4, r4, 0, ~TCR_DIE
+ mtspr SPRN_TCR, r4
+
+ mfspr r4, SPRN_TSR
+ oris r4, r4, TSR_DIS@h
+ mtspr SPRN_TSR, r4
+
+ /* set PMRCCR[VRCNT] to wait power stable for 40ms */
+ LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + PMRCCR_OFFSET)
+ lwz r4, 0(r3)
+ li r5, 0x12
+ rlwimi r4, r5, 0, PMRCCR_VRCNT_PRE_MASK
+ li r5, 0xa3
+ rlwimi r4, r5, 0, PMRCCR_VRCNT_MASK
+ stw r4, 0(r3)
+ lwz r4, 0(r3)
+
+ /* set deep sleep bit in POWMGTSCR */
+ lis r3, powmgtreq@ha
+ lwz r8, powmgtreq@l(r3)
+ LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + POWMGTSCR_OFFSET)
+ lwz r4, 0(r3)
+ or r4, r4, r8
+ stw r4, 0(r3)
+ lwz r4, 0(r3) /* read-back to flush write */
+ twi 0, r4, 0
+ isync
+
+ mftb r5
+1: /* spin until either we enter deep sleep, or the sleep process is
+ * aborted due to a pending wakeup event. Wait some time between
+ * accesses, so we don't flood the bus and prevent the pmc from
+ * detecting an idle system.
+ */
+
+ mftb r4
+ subf r7, r5, r4
+ cmpwi r7, 1000
+ blt 1b
+ mr r5, r4
+
+ lwz r6, 0(r3)
+ andis. r6, r6, POWMGTSCR_DPSLP@h
+ bne 1b
+ b 2f
+
+2: mfspr r4, SPRN_PIR
+ andi. r4, r4, 1
+99: bne 99b
+
+ /* Establish a temporary 64MB 0->0 mapping in TLB1[1]. */
+ LOAD_REG_IMMEDIATE(r4, MAS0_TLBSEL(1) | MAS0_ESEL(1))
+ mtspr SPRN_MAS0, r4
+ LOAD_REG_IMMEDIATE(r4,
+ MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(BOOK3E_PAGESZ_64M))
+ mtspr SPRN_MAS1, r4
+ li r4, 0
+ mtspr SPRN_MAS2, r4
+ li r4, (MAS3_SX | MAS3_SW | MAS3_SR)
+ mtspr SPRN_MAS3, r4
+ li r4, 0
+ mtspr SPRN_MAS7, r4
+ isync
+ tlbwe
+ isync
+
+ lis r3, (3f - PAGE_OFFSET)@h
+ ori r3, r3, (3f - PAGE_OFFSET)@l
+ mtctr r3
+ bctr
+
+ /* Locate the resume vector in the last word of the current page. */
+ . = mpc85xx_enter_deep_sleep + 0xffc
+mpc85xx_deep_resume:
+ b 2b
+
+3:
+ /* Restore the contents of TLB1[0]. It is assumed that it covers
+ * the currently executing code and the sleep save area, and that
+ * it does not alias our temporary mapping (which is at virtual zero).
+ */
+ lis r3, (TLBCAM - PAGE_OFFSET)@h
+ ori r3, r3, (TLBCAM - PAGE_OFFSET)@l
+
+ lwz r4, 0(r3)
+ lwz r5, 4(r3)
+ lwz r6, 8(r3)
+ lwz r7, 12(r3)
+ lwz r8, 16(r3)
+
+ mtspr SPRN_MAS0, r4
+ mtspr SPRN_MAS1, r5
+ mtspr SPRN_MAS2, r6
+ mtspr SPRN_MAS3, r7
+ mtspr SPRN_MAS7, r8
+
+ isync
+ tlbwe
+ isync
+
+ /* Access the ccsrbase address with TLB1[0] */
+ lis r5, ccsrbase_low@ha
+ lwz r4, ccsrbase_low@l(r5)
+ lis r5, ccsrbase_high@ha
+ lwz r3, ccsrbase_high@l(r5)
+
+ /* Use TLB1[15] to map the CCSR at 0xf0000000 */
+ LOAD_REG_IMMEDIATE(r5, MAS0_TLBSEL(1) | MAS0_ESEL(15))
+ mtspr SPRN_MAS0, r5
+ LOAD_REG_IMMEDIATE(r5,
+ MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(BOOK3E_PAGESZ_1M))
+ mtspr SPRN_MAS1, r5
+ LOAD_REG_IMMEDIATE(r5, CCSR_ADDR | MAS2_I | MAS2_M)
+ mtspr SPRN_MAS2, r5
+ rlwinm r5, r4, 0, MAS3_RPN
+ ori r5, r5, (MAS3_SW | MAS3_SR)
+ mtspr SPRN_MAS3, r5
+ mtspr SPRN_MAS7, r3
+ isync
+ tlbwe
+ isync
+
+ LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + L2C_OFFSET)
+ bl invalidate_enable_L2
+
+ /* Access the MEM(r10) with TLB1[0] */
+ lis r10, mpc85xx_sleep_save_area@h
+ ori r10, r10, mpc85xx_sleep_save_area@l
+
+ LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + BPTR_OFFSET)
+ lwz r4, SS_BPTR(r10)
+ stw r4, 0(r3) /* restore BPTR */
+
+ /* Program shift running space to PAGE_OFFSET */
+ mfmsr r3
+ lis r4, 1f@h
+ ori r4, r4, 1f@l
+
+ mtsrr1 r3
+ mtsrr0 r4
+ rfi
+
+1: /* Restore the rest of TLB1, in ascending order so that
+ * the TLB1[1] gets invalidated first.
+ *
+ * XXX: It's better to invalidate the temporary mapping
+ * TLB1[15] for CCSR before restore any TLB1 entry include 0.
+ */
+ LOAD_REG_IMMEDIATE(r4, MAS0_TLBSEL(1) | MAS0_ESEL(15))
+ mtspr SPRN_MAS0, r4
+ lis r4, 0
+ mtspr SPRN_MAS1, r4
+ isync
+ tlbwe
+ isync
+
+ lis r3, (TLBCAM + 5*4 - 4)@h
+ ori r3, r3, (TLBCAM + 5*4 - 4)@l
+ li r4, 15
+ mtctr r4
+
+2:
+ lwz r5, 4(r3)
+ lwz r6, 8(r3)
+ lwz r7, 12(r3)
+ lwz r8, 16(r3)
+ lwzu r9, 20(r3)
+
+ mtspr SPRN_MAS0, r5
+ mtspr SPRN_MAS1, r6
+ mtspr SPRN_MAS2, r7
+ mtspr SPRN_MAS3, r8
+ mtspr SPRN_MAS7, r9
+
+ isync
+ tlbwe
+ isync
+ bdnz 2b
+
+ lis r10, mpc85xx_sleep_save_area@h
+ ori r10, r10, mpc85xx_sleep_save_area@l
+
+ lwz r5, SS_HID+0(r10)
+ lwz r6, SS_HID+4(r10)
+
+ isync
+ mtspr SPRN_HID0, r5
+ isync
+
+ msync
+ mtspr SPRN_HID1, r6
+ isync
+
+ lwz r4, SS_IAC+0(r10)
+ lwz r5, SS_IAC+4(r10)
+ lwz r6, SS_DAC+0(r10)
+ lwz r7, SS_DAC+4(r10)
+
+ mtspr SPRN_IAC1, r4
+ mtspr SPRN_IAC2, r5
+ mtspr SPRN_DAC1, r6
+ mtspr SPRN_DAC2, r7
+
+ lwz r4, SS_DBCR+0(r10)
+ lwz r5, SS_DBCR+4(r10)
+ lwz r6, SS_DBCR+8(r10)
+
+ mtspr SPRN_DBCR0, r4
+ mtspr SPRN_DBCR1, r5
+ mtspr SPRN_DBCR2, r6
+
+ lwz r4, SS_PID+0(r10)
+ lwz r5, SS_PID+4(r10)
+ lwz r6, SS_PID+8(r10)
+
+ mtspr SPRN_PID0, r4
+ mtspr SPRN_PID1, r5
+ mtspr SPRN_PID2, r6
+
+ lwz r4, SS_SPRG+0x00(r10)
+ lwz r5, SS_SPRG+0x04(r10)
+ lwz r6, SS_SPRG+0x08(r10)
+ lwz r7, SS_SPRG+0x0c(r10)
+
+ mtspr SPRN_SPRG0, r4
+ mtspr SPRN_SPRG1, r5
+ mtspr SPRN_SPRG2, r6
+ mtspr SPRN_SPRG3, r7
+
+ lwz r4, SS_SPRG+0x10(r10)
+ lwz r5, SS_SPRG+0x14(r10)
+ lwz r6, SS_SPRG+0x18(r10)
+ lwz r7, SS_SPRG+0x1c(r10)
+
+ mtspr SPRN_SPRG4, r4
+ mtspr SPRN_SPRG5, r5
+ mtspr SPRN_SPRG6, r6
+ mtspr SPRN_SPRG7, r7
+
+ lwz r4, SS_IVPR(r10)
+ mtspr SPRN_IVPR, r4
+
+ lwz r4, SS_IVOR+0x00(r10)
+ lwz r5, SS_IVOR+0x04(r10)
+ lwz r6, SS_IVOR+0x08(r10)
+ lwz r7, SS_IVOR+0x0c(r10)
+
+ mtspr SPRN_IVOR0, r4
+ mtspr SPRN_IVOR1, r5
+ mtspr SPRN_IVOR2, r6
+ mtspr SPRN_IVOR3, r7
+
+ lwz r4, SS_IVOR+0x10(r10)
+ lwz r5, SS_IVOR+0x14(r10)
+ lwz r6, SS_IVOR+0x18(r10)
+ lwz r7, SS_IVOR+0x1c(r10)
+
+ mtspr SPRN_IVOR4, r4
+ mtspr SPRN_IVOR5, r5
+ mtspr SPRN_IVOR6, r6
+ mtspr SPRN_IVOR7, r7
+
+ lwz r4, SS_IVOR+0x20(r10)
+ lwz r5, SS_IVOR+0x24(r10)
+ lwz r6, SS_IVOR+0x28(r10)
+ lwz r7, SS_IVOR+0x2c(r10)
+
+ mtspr SPRN_IVOR8, r4
+ mtspr SPRN_IVOR9, r5
+ mtspr SPRN_IVOR10, r6
+ mtspr SPRN_IVOR11, r7
+
+ lwz r4, SS_IVOR+0x30(r10)
+ lwz r5, SS_IVOR+0x34(r10)
+ lwz r6, SS_IVOR+0x38(r10)
+ lwz r7, SS_IVOR+0x3c(r10)
+
+ mtspr SPRN_IVOR12, r4
+ mtspr SPRN_IVOR13, r5
+ mtspr SPRN_IVOR14, r6
+ mtspr SPRN_IVOR15, r7
+
+ lwz r4, SS_IVOR+0x40(r10)
+ lwz r5, SS_IVOR+0x44(r10)
+ lwz r6, SS_IVOR+0x48(r10)
+ lwz r7, SS_IVOR+0x4c(r10)
+
+ mtspr SPRN_IVOR32, r4
+ mtspr SPRN_IVOR33, r5
+ mtspr SPRN_IVOR34, r6
+ mtspr SPRN_IVOR35, r7
+
+ lwz r4, SS_TCR(r10)
+ lwz r5, SS_BUCSR(r10)
+ lwz r6, SS_L1CSR+0(r10)
+ lwz r7, SS_L1CSR+4(r10)
+ lwz r8, SS_USPRG+0(r10)
+
+ mtspr SPRN_TCR, r4
+ mtspr SPRN_BUCSR, r5
+
+ msync
+ isync
+ mtspr SPRN_L1CSR0, r6
+ isync
+
+ mtspr SPRN_L1CSR1, r7
+ isync
+
+ mtspr SPRN_USPRG0, r8
+
+ lmw r12, SS_GPREG(r10)
+
+ lwz r1, SS_SP(r10)
+ lwz r2, SS_CURRENT(r10)
+ lwz r4, SS_MSR(r10)
+ lwz r5, SS_LR(r10)
+ lwz r6, SS_CR(r10)
+
+ msync
+ mtmsr r4
+ isync
+
+ mtlr r5
+ mtcr r6
+
+ li r4, 0
+ mtspr SPRN_TBWL, r4
+
+ lwz r4, SS_TB+0(r10)
+ lwz r5, SS_TB+4(r10)
+
+ mtspr SPRN_TBWU, r4
+ mtspr SPRN_TBWL, r5
+
+ lis r3, 1
+ mtdec r3
+
+ blr
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 592a0f8..6c2c8b3 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -2,6 +2,7 @@
* Suspend/resume support
*
* Copyright 2009 MontaVista Software, Inc.
+ * Copyright 2010-2013 Freescale Semiconductor Inc.
*
* Author: Anton Vorontsov <[email protected]>
*
@@ -19,39 +20,88 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/of_platform.h>
+#include <linux/pm.h>
+#include <asm/cacheflush.h>
+#include <asm/switch_to.h>
+
+#include <sysdev/fsl_soc.h>

struct pmc_regs {
+ /* 0xe0070: Device disable control register */
__be32 devdisr;
+ /* 0xe0074: 2nd Device disable control register */
__be32 devdisr2;
- __be32 :32;
- __be32 :32;
- __be32 pmcsr;
-#define PMCSR_SLP (1 << 17)
+ __be32 res1;
+ /* 0xe007c: Power Management Jog Control Register */
+ __be32 pmjcr;
+ /* 0xe0080: Power management control and status register */
+ __be32 powmgtcsr;
+#define POWMGTCSR_SLP 0x00020000
+#define POWMGTCSR_DPSLP 0x00100000
+ __be32 res3[2];
+ /* 0xe008c: Power management clock disable register */
+ __be32 pmcdr;
};

-static struct device *pmc_dev;
static struct pmc_regs __iomem *pmc_regs;
+static unsigned int pmc_flag;
+
+#define PMC_SLEEP 0x1
+#define PMC_DEEP_SLEEP 0x2

static int pmc_suspend_enter(suspend_state_t state)
{
- int ret;
+ int ret = 0;
+
+ switch (state) {
+#ifdef CONFIG_PPC_85xx
+ case PM_SUSPEND_MEM:
+#ifdef CONFIG_SPE
+ enable_kernel_spe();
+#endif
+ enable_kernel_fp();
+
+ pr_debug("%s: Entering deep sleep\n", __func__);
+
+ mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_DPSLP);
+
+ pr_debug("%s: Resumed from deep sleep\n", __func__);
+ break;
+#endif
+
+ case PM_SUSPEND_STANDBY:
+#ifdef CONFIG_FSL_SOC_BOOKE
+ flush_dcache_L1();
+#endif
+ setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_SLP);

- setbits32(&pmc_regs->pmcsr, PMCSR_SLP);
- /* At this point, the CPU is asleep. */
+ /* At this point, the CPU is asleep. */

- /* Upon resume, wait for SLP bit to be clear. */
- ret = spin_event_timeout((in_be32(&pmc_regs->pmcsr) & PMCSR_SLP) == 0,
- 10000, 10) ? 0 : -ETIMEDOUT;
- if (ret)
- dev_err(pmc_dev, "tired waiting for SLP bit to clear\n");
+ /* Upon resume, wait for SLP bit to be clear. */
+ ret = spin_event_timeout(
+ (in_be32(&pmc_regs->powmgtcsr) & POWMGTCSR_SLP) == 0,
+ 10000, 10);
+ if (!ret) {
+ pr_err("%s: timeout waiting for SLP bit to be cleared\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+
+ }
return ret;
}

static int pmc_suspend_valid(suspend_state_t state)
{
- if (state != PM_SUSPEND_STANDBY)
+ if (((pmc_flag & PMC_SLEEP) && (state == PM_SUSPEND_STANDBY)) ||
+ ((pmc_flag & PMC_DEEP_SLEEP) && (state == PM_SUSPEND_MEM)))
+ return 1;
+ else
return 0;
- return 1;
}

static const struct platform_suspend_ops pmc_suspend_ops = {
@@ -59,14 +109,26 @@ static const struct platform_suspend_ops pmc_suspend_ops = {
.enter = pmc_suspend_enter,
};

-static int pmc_probe(struct platform_device *ofdev)
+static int pmc_probe(struct platform_device *pdev)
{
- pmc_regs = of_iomap(ofdev->dev.of_node, 0);
+ struct device_node *np = pdev->dev.of_node;
+
+ pmc_regs = of_iomap(np, 0);
if (!pmc_regs)
return -ENOMEM;

- pmc_dev = &ofdev->dev;
+ pmc_flag = PMC_SLEEP;
+ if (of_device_is_compatible(np, "fsl,mpc8536-pmc"))
+ pmc_flag |= PMC_DEEP_SLEEP;
+
+ if (of_device_is_compatible(np, "fsl,p1022-pmc"))
+ pmc_flag |= PMC_DEEP_SLEEP;
+
suspend_set_ops(&pmc_suspend_ops);
+
+ pr_info("Freescale PMC driver: sleep(standby)%s\n",
+ (pmc_flag & PMC_DEEP_SLEEP) ? ", deep sleep(mem)" : "");
+
return 0;
}

diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index c6d0073..949377d 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -48,5 +48,10 @@ extern struct platform_diu_data_ops diu_ops;
void fsl_hv_restart(char *cmd);
void fsl_hv_halt(void);

+/*
+ * Cast the ccsrbar to 64-bit parameter so that the assembly
+ * code can be compatible with both 32-bit & 36-bit.
+ */
+extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
#endif
#endif
--
1.7.3

2013-04-19 10:51:30

by Chenhui Zhao

[permalink] [raw]
Subject: [PATCH v2 03/15] fsl_pmc: Add API to enable device as wakeup event source

From: chenhui zhao <[email protected]>

Add APIs for setting wakeup source and lossless Ethernet in low power modes.
These APIs can be used by wake-on-packet feature.

Change-Id: I1803dcd4571af1eac49b43d99c578e7f99e2c278
Signed-off-by: Dave Liu <[email protected]>
Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Jin Qing <[email protected]>
Signed-off-by: Zhao Chenhui <[email protected]>
---
arch/powerpc/sysdev/fsl_pmc.c | 72 ++++++++++++++++++++++++++++++++++++++++-
arch/powerpc/sysdev/fsl_soc.h | 11 ++++++
2 files changed, 82 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 6c2c8b3..94ae476 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -38,6 +38,7 @@ struct pmc_regs {
__be32 powmgtcsr;
#define POWMGTCSR_SLP 0x00020000
#define POWMGTCSR_DPSLP 0x00100000
+#define POWMGTCSR_LOSSLESS 0x00400000
__be32 res3[2];
/* 0xe008c: Power management clock disable register */
__be32 pmcdr;
@@ -48,6 +49,75 @@ static unsigned int pmc_flag;

#define PMC_SLEEP 0x1
#define PMC_DEEP_SLEEP 0x2
+#define PMC_LOSSLESS 0x4
+
+/**
+ * mpc85xx_pmc_set_wake - enable devices as wakeup event source
+ * @dev: a device affected
+ * @enable: True to enable event generation; false to disable
+ *
+ * This enables the device as a wakeup event source, or disables it.
+ *
+ * RETURN VALUE:
+ * 0 is returned on success.
+ * -EINVAL is returned if device is not supposed to wake up the system.
+ * -ENODEV is returned if PMC is unavailable.
+ * Error code depending on the platform is returned if both the platform and
+ * the native mechanism fail to enable the generation of wake-up events
+ */
+int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+ int ret = 0;
+ struct device_node *clk_np;
+ const u32 *prop;
+ u32 pmcdr_mask;
+
+ if (!pmc_regs) {
+ dev_err(dev, "%s: PMC is unavailable\n", __func__);
+ return -ENODEV;
+ }
+
+ if (enable && !device_may_wakeup(dev))
+ return -EINVAL;
+
+ clk_np = of_parse_phandle(dev->of_node, "fsl,pmc-handle", 0);
+ if (!clk_np)
+ return -EINVAL;
+
+ prop = of_get_property(clk_np, "fsl,pmcdr-mask", NULL);
+ if (!prop) {
+ ret = -EINVAL;
+ goto out;
+ }
+ pmcdr_mask = be32_to_cpup(prop);
+
+ if (enable)
+ /* clear to enable clock in low power mode */
+ clrbits32(&pmc_regs->pmcdr, pmcdr_mask);
+ else
+ setbits32(&pmc_regs->pmcdr, pmcdr_mask);
+
+out:
+ of_node_put(clk_np);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_wake);
+
+/**
+ * mpc85xx_pmc_set_lossless_ethernet - enable lossless ethernet
+ * in (deep) sleep mode
+ * @enable: True to enable event generation; false to disable
+ */
+void mpc85xx_pmc_set_lossless_ethernet(int enable)
+{
+ if (pmc_flag & PMC_LOSSLESS) {
+ if (enable)
+ setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
+ else
+ clrbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
+ }
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_lossless_ethernet);

static int pmc_suspend_enter(suspend_state_t state)
{
@@ -122,7 +192,7 @@ static int pmc_probe(struct platform_device *pdev)
pmc_flag |= PMC_DEEP_SLEEP;

if (of_device_is_compatible(np, "fsl,p1022-pmc"))
- pmc_flag |= PMC_DEEP_SLEEP;
+ pmc_flag |= PMC_DEEP_SLEEP | PMC_LOSSLESS;

suspend_set_ops(&pmc_suspend_ops);

diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 949377d..e58f4dd 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -21,6 +21,17 @@ struct device_node;

extern void fsl_rstcr_restart(char *cmd);

+#ifdef CONFIG_FSL_PMC
+int mpc85xx_pmc_set_wake(struct device *dev, bool enable);
+void mpc85xx_pmc_set_lossless_ethernet(int enable);
+#else
+static inline int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+ return -ENODEV;
+}
+#define mpc85xx_pmc_set_lossless_ethernet(enable) do { } while (0)
+#endif
+
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)

/* The different ports that the DIU can be connected to */
--
1.7.3

2013-04-22 03:25:37

by Viresh Kumar

[permalink] [raw]
Subject: Re: [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface

On Fri, Apr 19, 2013 at 4:17 PM, Zhao Chenhui
<[email protected]> wrote:
> diff --git a/drivers/cpufreq/mpc85xx-cpufreq.c b/drivers/cpufreq/mpc85xx-cpufreq.c

> +#include <linux/module.h>
> +#include <linux/cpufreq.h>
> +#include <linux/of_platform.h>
> +#include <linux/suspend.h>
> +#include <linux/cpu.h>
> +#include <linux/time.h>
> +#include <linux/io.h>
> +#include <linux/smp.h>

Would be better to keep them in alphabetical order, so that we don't add
anything twice.

> +static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
> +{
> + unsigned int i, cur_pll;
> + int hw_cpu = get_hard_smp_processor_id(policy->cpu);
> +
> + if (!cpu_present(policy->cpu))

This can't happen and so no need to check it.

> + return -ENODEV;
> +
> + /* the latency of a transition, the unit is ns */
> + policy->cpuinfo.transition_latency = 2000;
> +
> + cur_pll = get_pll(hw_cpu);
> +
> + /* initialize frequency table */
> + pr_debug("core%d frequency table:\n", hw_cpu);
> + for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
> + if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
> + /* The frequency unit is kHz. */
> + mpc85xx_freqs[i].frequency =
> + (sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
> + } else {
> + mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
> + }
> +
> + pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
> +
> + if (mpc85xx_freqs[i].index == cur_pll)
> + policy->cur = mpc85xx_freqs[i].frequency;
> + }
> + pr_debug("current pll is at %d, and core freq is%d\n",
> + cur_pll, policy->cur);
> +
> + cpufreq_frequency_table_get_attr(mpc85xx_freqs, policy->cpu);
> +
> + /*
> + * This ensures that policy->cpuinfo_min
> + * and policy->cpuinfo_max are set correctly.
> + */
> + return cpufreq_frequency_table_cpuinfo(policy, mpc85xx_freqs);

Call cpufreq_frequency_table_get_attr() at the end after above call is
successful.

> +}

> +static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
> + unsigned int target_freq,
> + unsigned int relation)

merge above two lines.

> +{
> + struct cpufreq_freqs freqs;
> + unsigned int new;
> + int ret = 0;
> +
> + if (!set_pll)
> + return -ENODEV;
> +
> + cpufreq_frequency_table_target(policy,
> + mpc85xx_freqs,
> + target_freq,
> + relation,
> + &new);

same.. merge all above to put it in a single line.

> + freqs.old = policy->cur;
> + freqs.new = mpc85xx_freqs[new].frequency;
> + freqs.cpu = policy->cpu;

not required now.

> + mutex_lock(&mpc85xx_switch_mutex);
> + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);

ditto. Rebase over latest code from linux-next. This call has changed.

> + ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
> + if (!ret) {
> + pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
> + policy->cpu, mpc85xx_freqs[new].frequency,
> + mpc85xx_freqs[new].index);
> +
> + ppc_proc_freq = freqs.new * 1000ul;
> + }
> + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> + mutex_unlock(&mpc85xx_switch_mutex);
> +
> + return ret;
> +}

> +static int __init mpc85xx_jog_init(void)
> +{
> + struct device_node *np;
> + unsigned int svr;
> +
> + np = of_find_matching_node(NULL, mpc85xx_jog_ids);
> + if (!np)
> + return -ENODEV;
> +
> + guts = of_iomap(np, 0);
> + if (!guts) {
> + of_node_put(np);
> + return -ENODEV;
> + }
> +
> + sysfreq = fsl_get_sys_freq();
> +
> + if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
> + svr = mfspr(SPRN_SVR);
> + if ((svr & 0x7fff) == 0x10) {
> + pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
> + of_node_put(np);

unmap too??

> + return -ENODEV;
> + }
> + mpc85xx_freqs = mpc8536_freqs_table;
> + set_pll = mpc8536_set_pll;
> + max_pll[0] = get_pll(0);
> +
> + } else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
> + mpc85xx_freqs = p1022_freqs_table;
> + set_pll = p1022_set_pll;
> + max_pll[0] = get_pll(0);
> + max_pll[1] = get_pll(1);
> + }
> +
> + pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
> +
> + of_node_put(np);
> + return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
> +}
> +
> +device_initcall(mpc85xx_jog_init);

2013-04-22 10:56:28

by Chenhui Zhao

[permalink] [raw]
Subject: Re: [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface

On Mon, Apr 22, 2013 at 08:55:35AM +0530, Viresh Kumar wrote:
> On Fri, Apr 19, 2013 at 4:17 PM, Zhao Chenhui
> <[email protected]> wrote:
> > diff --git a/drivers/cpufreq/mpc85xx-cpufreq.c b/drivers/cpufreq/mpc85xx-cpufreq.c
>
> > +#include <linux/module.h>
> > +#include <linux/cpufreq.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/suspend.h>
> > +#include <linux/cpu.h>
> > +#include <linux/time.h>
> > +#include <linux/io.h>
> > +#include <linux/smp.h>
>
> Would be better to keep them in alphabetical order, so that we don't add
> anything twice.

Good idea.

>
> > +static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
> > +{
> > + unsigned int i, cur_pll;
> > + int hw_cpu = get_hard_smp_processor_id(policy->cpu);
> > +
> > + if (!cpu_present(policy->cpu))
>
> This can't happen and so no need to check it.
>
> > + return -ENODEV;
> > +
> > + /* the latency of a transition, the unit is ns */
> > + policy->cpuinfo.transition_latency = 2000;
> > +
> > + cur_pll = get_pll(hw_cpu);
> > +
> > + /* initialize frequency table */
> > + pr_debug("core%d frequency table:\n", hw_cpu);
> > + for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
> > + if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
> > + /* The frequency unit is kHz. */
> > + mpc85xx_freqs[i].frequency =
> > + (sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
> > + } else {
> > + mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
> > + }
> > +
> > + pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
> > +
> > + if (mpc85xx_freqs[i].index == cur_pll)
> > + policy->cur = mpc85xx_freqs[i].frequency;
> > + }
> > + pr_debug("current pll is at %d, and core freq is%d\n",
> > + cur_pll, policy->cur);
> > +
> > + cpufreq_frequency_table_get_attr(mpc85xx_freqs, policy->cpu);
> > +
> > + /*
> > + * This ensures that policy->cpuinfo_min
> > + * and policy->cpuinfo_max are set correctly.
> > + */
> > + return cpufreq_frequency_table_cpuinfo(policy, mpc85xx_freqs);
>
> Call cpufreq_frequency_table_get_attr() at the end after above call is
> successful.
>
> > +}
>
> > +static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
> > + unsigned int target_freq,
> > + unsigned int relation)
>
> merge above two lines.
>
> > +{
> > + struct cpufreq_freqs freqs;
> > + unsigned int new;
> > + int ret = 0;
> > +
> > + if (!set_pll)
> > + return -ENODEV;
> > +
> > + cpufreq_frequency_table_target(policy,
> > + mpc85xx_freqs,
> > + target_freq,
> > + relation,
> > + &new);
>
> same.. merge all above to put it in a single line.
>
> > + freqs.old = policy->cur;
> > + freqs.new = mpc85xx_freqs[new].frequency;
> > + freqs.cpu = policy->cpu;
>
> not required now.
>
> > + mutex_lock(&mpc85xx_switch_mutex);
> > + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
>
> ditto. Rebase over latest code from linux-next. This call has changed.
>
> > + ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
> > + if (!ret) {
> > + pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
> > + policy->cpu, mpc85xx_freqs[new].frequency,
> > + mpc85xx_freqs[new].index);
> > +
> > + ppc_proc_freq = freqs.new * 1000ul;
> > + }
> > + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> > + mutex_unlock(&mpc85xx_switch_mutex);
> > +
> > + return ret;
> > +}
>
> > +static int __init mpc85xx_jog_init(void)
> > +{
> > + struct device_node *np;
> > + unsigned int svr;
> > +
> > + np = of_find_matching_node(NULL, mpc85xx_jog_ids);
> > + if (!np)
> > + return -ENODEV;
> > +
> > + guts = of_iomap(np, 0);
> > + if (!guts) {
> > + of_node_put(np);
> > + return -ENODEV;
> > + }
> > +
> > + sysfreq = fsl_get_sys_freq();
> > +
> > + if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
> > + svr = mfspr(SPRN_SVR);
> > + if ((svr & 0x7fff) == 0x10) {
> > + pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
> > + of_node_put(np);
>
> unmap too??
>
> > + return -ENODEV;
> > + }
> > + mpc85xx_freqs = mpc8536_freqs_table;
> > + set_pll = mpc8536_set_pll;
> > + max_pll[0] = get_pll(0);
> > +
> > + } else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
> > + mpc85xx_freqs = p1022_freqs_table;
> > + set_pll = p1022_set_pll;
> > + max_pll[0] = get_pll(0);
> > + max_pll[1] = get_pll(1);
> > + }
> > +
> > + pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
> > +
> > + of_node_put(np);
> > + return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
> > +}
> > +
> > +device_initcall(mpc85xx_jog_init);
>

Thanks. I will fix them.

-Chenhui

2013-04-23 09:53:56

by Chenhui Zhao

[permalink] [raw]
Subject: Re: [linuxppc-release] [PATCH v2 01/15] powerpc/85xx: cache operations for Freescale SoCs based on BOOK3E

Hi Kumar, Scott,

Do you have any comments on this set of patches?

Best Regards,
-Chenhui

On Fri, Apr 19, 2013 at 06:47:34PM +0800, Zhao Chenhui wrote:
> These cache operations support Freescale SoCs based on BOOK3E.
> Move L1 cache operations to fsl_booke_cache.S in order to maintain
> easily. And, add cache operations for backside L2 cache and platform cache.
>
> The backside L2 cache appears on e500mc and e5500 core. The platform cache
> supported by this patch is L2 Look-Aside Cache, which appears on SoCs
> with e500v1/e500v2 core, such as MPC8572, P1020, etc.
>
> Signed-off-by: Zhao Chenhui <[email protected]>
> Signed-off-by: Li Yang <[email protected]>
> ---
> arch/powerpc/include/asm/cacheflush.h | 8 ++
> arch/powerpc/kernel/Makefile | 1 +
> arch/powerpc/kernel/fsl_booke_cache.S | 210 +++++++++++++++++++++++++++++++++
> arch/powerpc/kernel/head_fsl_booke.S | 74 ------------
> 4 files changed, 219 insertions(+), 74 deletions(-)
> create mode 100644 arch/powerpc/kernel/fsl_booke_cache.S
>

2013-04-23 23:46:17

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 01/15] powerpc/85xx: cache operations for Freescale SoCs based on BOOK3E

On 04/19/2013 05:47:34 AM, Zhao Chenhui wrote:
> These cache operations support Freescale SoCs based on BOOK3E.
> Move L1 cache operations to fsl_booke_cache.S in order to maintain
> easily. And, add cache operations for backside L2 cache and platform
> cache.
>
> The backside L2 cache appears on e500mc and e5500 core. The platform
> cache
> supported by this patch is L2 Look-Aside Cache, which appears on SoCs
> with e500v1/e500v2 core, such as MPC8572, P1020, etc.
>
> Signed-off-by: Zhao Chenhui <[email protected]>
> Signed-off-by: Li Yang <[email protected]>
> ---
> arch/powerpc/include/asm/cacheflush.h | 8 ++
> arch/powerpc/kernel/Makefile | 1 +
> arch/powerpc/kernel/fsl_booke_cache.S | 210
> +++++++++++++++++++++++++++++++++
> arch/powerpc/kernel/head_fsl_booke.S | 74 ------------
> 4 files changed, 219 insertions(+), 74 deletions(-)
> create mode 100644 arch/powerpc/kernel/fsl_booke_cache.S
>
> diff --git a/arch/powerpc/include/asm/cacheflush.h
> b/arch/powerpc/include/asm/cacheflush.h
> index b843e35..bc3f937 100644
> --- a/arch/powerpc/include/asm/cacheflush.h
> +++ b/arch/powerpc/include/asm/cacheflush.h
> @@ -32,6 +32,14 @@ extern void flush_dcache_page(struct page *page);
>
> extern void __flush_disable_L1(void);
>
> +#ifdef CONFIG_FSL_SOC_BOOKE
> +void flush_dcache_L1(void);
> +void flush_backside_L2_cache(void);
> +void disable_backside_L2_cache(void);
> +void flush_disable_L2(void);
> +void invalidate_enable_L2(void);
> +#endif

Don't ifdef prototypes unless there's a good reason, such as providing
an inline alternative.

Why do you have "flush_backside_L2_cache" and
"disable_backside_L2_cache" as something different from
"flush_disable_L2"? The latter should flush whatever L2 is present.
Don't treat pre-corenet as the default.

Why do we even need to distinguish L1 from L2 at all? Shouldn't the
function that gets exposed just be "flush and disable data caches that
are specific to this cpu"? What should happen on e6500?

-Scott

2013-04-23 23:53:25

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 02/15] powerpc/85xx: add sleep and deep sleep support

On 04/19/2013 05:47:35 AM, Zhao Chenhui wrote:
> static int pmc_suspend_enter(suspend_state_t state)
> {
> - int ret;
> + int ret = 0;
> +
> + switch (state) {
> +#ifdef CONFIG_PPC_85xx
> + case PM_SUSPEND_MEM:
> +#ifdef CONFIG_SPE
> + enable_kernel_spe();
> +#endif
> + enable_kernel_fp();

Why does enable_kernel_spe() need an ifdef but enable_kernel_fp()
doesn't?

> + case PM_SUSPEND_STANDBY:
> +#ifdef CONFIG_FSL_SOC_BOOKE
> + flush_dcache_L1();
> +#endif
> + setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_SLP);

Only L1, even on e500mc?

-Scott

2013-04-23 23:59:09

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 07/15] powerpc/85xx: add time base sync for SoCs based on e500mc/e5500

On 04/19/2013 05:47:40 AM, Zhao Chenhui wrote:
> From: Chen-Hui Zhao <[email protected]>
>
> In the case of SMP, during the time base sync period, all time bases
> of
> online cores must stop, then start simultaneously.
>
> There is a RCPM (Run Control/Power Management) module in CoreNet
> based SoCs.
> Define a struct ccsr_rcpm to describe the register map.
>
> This patch supports SoCs based on e500mc/e5500, such as P4080, P5020,
> etc.
>
> Signed-off-by: Zhao Chenhui <[email protected]>
> Signed-off-by: Li Yang <[email protected]>
> ---
> arch/powerpc/include/asm/fsl_guts.h | 38
> +++++++++++++++++++++++++++++++++++
> arch/powerpc/platforms/85xx/smp.c | 32
> +++++++++++++++++++++++++++++
> 2 files changed, 70 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/fsl_guts.h
> b/arch/powerpc/include/asm/fsl_guts.h
> index 77ced0b..4eac1cf 100644
> --- a/arch/powerpc/include/asm/fsl_guts.h
> +++ b/arch/powerpc/include/asm/fsl_guts.h
> @@ -106,6 +106,44 @@ struct ccsr_guts {
> /* Alternate function signal multiplex control */
> #define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x))
>
> +struct ccsr_rcpm {
> + u8 res0000[4];
> + __be32 cdozsr; /* 0x0004 - Core Doze Status Register */
> + u8 res0008[4];
> + __be32 cdozcr; /* 0x000c - Core Doze Control Register
> */
> + u8 res0010[4];
> + __be32 cnapsr; /* 0x0014 - Core Nap Status Register */
> + u8 res0018[4];
> + __be32 cnapcr; /* 0x001c - Core Nap Control Register */
> + u8 res0020[4];
> + __be32 cdozpsr; /* 0x0024 - Core Doze Previous Status
> Register */
> + u8 res0028[4];
> + __be32 cnappsr; /* 0x002c - Core Nap Previous Status
> Register */
> + u8 res0030[4];
> + __be32 cwaitsr; /* 0x0034 - Core Wait Status Register */
> + u8 res0038[4];
> + __be32 cwdtdsr; /* 0x003c - Core watchdog detect status
> register */
> + __be32 powmgtcsr; /* 0x0040 - Power Mangement Control &
> Status Register */
> + u8 res0044[12];
> + __be32 ippdexpcr; /* 0x0050 - IP Powerdown Exception
> Control Register */
> + u8 res0054[16];
> + __be32 cpmimr; /* 0x0064 - Core PM IRQ Mask Register */
> + u8 res0068[4];
> + __be32 cpmcimr; /* 0x006c - Core PM Critical IRQ Mask
> Register */
> + u8 res0070[4];
> + __be32 cpmmcmr; /* 0x0074 - Core PM Machine Check Mask
> Register */
> + u8 res0078[4];
> + __be32 cpmnmimr; /* 0x007c - Core PM NMI Mask Register */
> + u8 res0080[4];
> + __be32 ctbenr; /* 0x0084 - Core Time Base Enable
> Register */
> + u8 res0088[4];
> + __be32 ctbckselr; /* 0x008c - Core Time Base Clock Select
> Register */
> + u8 res0090[4];
> + __be32 ctbhltcr; /* 0x0094 - Core Time Base Halt Control
> Register */
> + u8 res0098[4];
> + __be32 cmcpmaskcr; /* 0x00a4 - Core machine check mask
> control register */
> +};
> +
> #ifdef CONFIG_PPC_86xx
>
> #define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA
> controller/channel set to SSI */
> diff --git a/arch/powerpc/platforms/85xx/smp.c
> b/arch/powerpc/platforms/85xx/smp.c
> index 6a17599..6c2fe6b 100644
> --- a/arch/powerpc/platforms/85xx/smp.c
> +++ b/arch/powerpc/platforms/85xx/smp.c
> @@ -44,7 +44,36 @@ static struct ccsr_guts __iomem *guts;
> static u64 timebase;
> static int tb_req;
> static int tb_valid;
> +static u32 cur_booting_core;
>
> +#ifdef CONFIG_PPC_E500MC
> +/* get a physical mask of online cores and booting core */
> +static inline u32 get_phy_cpu_mask(void)
> +{
> + u32 mask;
> + int cpu;
> +
> + mask = 1 << cur_booting_core;
> + for_each_online_cpu(cpu)
> + mask |= 1 << get_hard_smp_processor_id(cpu);
> +
> + return mask;
> +}
> +
> +static void mpc85xx_timebase_freeze(int freeze)
> +{
> + struct ccsr_rcpm __iomem *rcpm = (typeof(rcpm))guts;
> + u32 mask = get_phy_cpu_mask();
> +
> + if (freeze)
> + clrbits32(&rcpm->ctbenr, mask);
> + else
> + setbits32(&rcpm->ctbenr, mask);
> +
> + /* read back to push the previos write */
> + in_be32(&rcpm->ctbenr);
> +}
> +#else

Please determine the timebase sync implementation at runtime, rather
than relying on our current inability to have e500v2 and e500mc in the
same kernel. e6500 will be different from e5500, but both can be in
the same kernel image.

-Scott

2013-04-24 00:00:59

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 13/15] powerpc/85xx: add support for e6500 L1 cache operation

On 04/19/2013 05:47:46 AM, Zhao Chenhui wrote:
> From: Chen-Hui Zhao <[email protected]>
>
> The L1 Data Cache of e6500 contains no modified data, no flush
> is required.
>
> Signed-off-by: Zhao Chenhui <[email protected]>
> Signed-off-by: Li Yang <[email protected]>
> Signed-off-by: Andy Fleming <[email protected]>
> ---
> arch/powerpc/kernel/fsl_booke_cache.S | 11 ++++++++++-
> 1 files changed, 10 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/kernel/fsl_booke_cache.S
> b/arch/powerpc/kernel/fsl_booke_cache.S
> index 232c47b..24a52bb 100644
> --- a/arch/powerpc/kernel/fsl_booke_cache.S
> +++ b/arch/powerpc/kernel/fsl_booke_cache.S
> @@ -65,13 +65,22 @@ _GLOBAL(flush_dcache_L1)
>
> blr
>
> +#define PVR_E6500 0x8040
> +
> /* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
> _GLOBAL(__flush_disable_L1)
> +/* L1 Data Cache of e6500 contains no modified data, no flush is
> required */
> + mfspr r3, SPRN_PVR
> + rlwinm r4, r3, 16, 0xffff
> + lis r5, 0
> + ori r5, r5, PVR_E6500@l
> + cmpw r4, r5
> + beq 2f
> mflr r10
> bl flush_dcache_L1 /* Flush L1 d-cache */
> mtlr r10
>
> - msync
> +2: msync
> mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
> li r5, 2
> rlwimi r4, r5, 0, 3

Note that disabling the cache is a core operation, rather than a thread
operation. Is this only called when the second thread is disabled?

-Scott

2013-04-24 00:04:18

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 12/15] powerpc/85xx: add time base sync support for e6500

On 04/19/2013 05:47:45 AM, Zhao Chenhui wrote:
> From: Chen-Hui Zhao <[email protected]>
>
> For e6500, two threads in one core share one time base. Just need
> to do time base sync on first thread of one core, and skip it on
> the other thread.
>
> Signed-off-by: Zhao Chenhui <[email protected]>
> Signed-off-by: Li Yang <[email protected]>
> Signed-off-by: Andy Fleming <[email protected]>
> ---
> arch/powerpc/platforms/85xx/smp.c | 52
> +++++++++++++++++++++++++++++++-----
> 1 files changed, 44 insertions(+), 8 deletions(-)
>
> diff --git a/arch/powerpc/platforms/85xx/smp.c
> b/arch/powerpc/platforms/85xx/smp.c
> index 74d8cde..5f3eee3 100644
> --- a/arch/powerpc/platforms/85xx/smp.c
> +++ b/arch/powerpc/platforms/85xx/smp.c
> @@ -26,6 +26,7 @@
> #include <asm/cacheflush.h>
> #include <asm/dbell.h>
> #include <asm/fsl_guts.h>
> +#include <asm/cputhreads.h>
>
> #include <sysdev/fsl_soc.h>
> #include <sysdev/mpic.h>
> @@ -45,6 +46,7 @@ static u64 timebase;
> static int tb_req;
> static int tb_valid;
> static u32 cur_booting_core;
> +static bool rcpmv2;
>
> #ifdef CONFIG_PPC_E500MC
> /* get a physical mask of online cores and booting core */
> @@ -53,26 +55,40 @@ static inline u32 get_phy_cpu_mask(void)
> u32 mask;
> int cpu;
>
> - mask = 1 << cur_booting_core;
> - for_each_online_cpu(cpu)
> - mask |= 1 << get_hard_smp_processor_id(cpu);
> + if (smt_capable()) {
> + /* two threads in one core share one time base */
> + mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> + for_each_online_cpu(cpu)
> + mask |= 1 << cpu_core_index_of_thread(
> + get_hard_smp_processor_id(cpu));
> + } else {
> + mask = 1 << cur_booting_core;
> + for_each_online_cpu(cpu)
> + mask |= 1 << get_hard_smp_processor_id(cpu);
> + }

Where is smt_capable defined()? I assume somewhere in the patchset but
it's a pain to search 12 patches...

Is this really about whether we're SMT-capable or whether we have rcpm
v2?

-Scott

2013-04-24 11:09:06

by Chenhui Zhao

[permalink] [raw]
Subject: Re: [PATCH v2 01/15] powerpc/85xx: cache operations for Freescale SoCs based on BOOK3E

On Tue, Apr 23, 2013 at 06:46:10PM -0500, Scott Wood wrote:
> On 04/19/2013 05:47:34 AM, Zhao Chenhui wrote:
> >These cache operations support Freescale SoCs based on BOOK3E.
> >Move L1 cache operations to fsl_booke_cache.S in order to maintain
> >easily. And, add cache operations for backside L2 cache and
> >platform cache.
> >
> >The backside L2 cache appears on e500mc and e5500 core. The
> >platform cache
> >supported by this patch is L2 Look-Aside Cache, which appears on SoCs
> >with e500v1/e500v2 core, such as MPC8572, P1020, etc.
> >
> >Signed-off-by: Zhao Chenhui <[email protected]>
> >Signed-off-by: Li Yang <[email protected]>
> >---
> > arch/powerpc/include/asm/cacheflush.h | 8 ++
> > arch/powerpc/kernel/Makefile | 1 +
> > arch/powerpc/kernel/fsl_booke_cache.S | 210
> >+++++++++++++++++++++++++++++++++
> > arch/powerpc/kernel/head_fsl_booke.S | 74 ------------
> > 4 files changed, 219 insertions(+), 74 deletions(-)
> > create mode 100644 arch/powerpc/kernel/fsl_booke_cache.S
> >
> >diff --git a/arch/powerpc/include/asm/cacheflush.h
> >b/arch/powerpc/include/asm/cacheflush.h
> >index b843e35..bc3f937 100644
> >--- a/arch/powerpc/include/asm/cacheflush.h
> >+++ b/arch/powerpc/include/asm/cacheflush.h
> >@@ -32,6 +32,14 @@ extern void flush_dcache_page(struct page *page);
> >
> > extern void __flush_disable_L1(void);
> >
> >+#ifdef CONFIG_FSL_SOC_BOOKE
> >+void flush_dcache_L1(void);
> >+void flush_backside_L2_cache(void);
> >+void disable_backside_L2_cache(void);
> >+void flush_disable_L2(void);
> >+void invalidate_enable_L2(void);
> >+#endif
>
> Don't ifdef prototypes unless there's a good reason, such as
> providing an inline alternative.

I'll get rid of this "#ifdef".

>
> Why do you have "flush_backside_L2_cache" and
> "disable_backside_L2_cache" as something different from
> "flush_disable_L2"? The latter should flush whatever L2 is present.
> Don't treat pre-corenet as the default.
>

These L2 caches are very different. The backside L2 is integrated in
the e500mc/e5500 core and controlled by SPR registers. But, the latter
L2 cache is on the SoC and controlled by registers mapped in CCSR.

> Why do we even need to distinguish L1 from L2 at all? Shouldn't the
> function that gets exposed just be "flush and disable data caches
> that are specific to this cpu"? What should happen on e6500?
>
> -Scott

Yes. It is a good idea to use a set of uniform functions to operate the caches of
e500/e500mc/e5500/e6500 and SoCs. I'll think over your comments.

Thanks for you comments.

-Chenhui

2013-04-24 11:15:18

by Chenhui Zhao

[permalink] [raw]
Subject: Re: [PATCH v2 13/15] powerpc/85xx: add support for e6500 L1 cache operation

On Tue, Apr 23, 2013 at 07:00:49PM -0500, Scott Wood wrote:
> On 04/19/2013 05:47:46 AM, Zhao Chenhui wrote:
> >From: Chen-Hui Zhao <[email protected]>
> >
> >The L1 Data Cache of e6500 contains no modified data, no flush
> >is required.
> >
> >Signed-off-by: Zhao Chenhui <[email protected]>
> >Signed-off-by: Li Yang <[email protected]>
> >Signed-off-by: Andy Fleming <[email protected]>
> >---
> > arch/powerpc/kernel/fsl_booke_cache.S | 11 ++++++++++-
> > 1 files changed, 10 insertions(+), 1 deletions(-)
> >
> >diff --git a/arch/powerpc/kernel/fsl_booke_cache.S
> >b/arch/powerpc/kernel/fsl_booke_cache.S
> >index 232c47b..24a52bb 100644
> >--- a/arch/powerpc/kernel/fsl_booke_cache.S
> >+++ b/arch/powerpc/kernel/fsl_booke_cache.S
> >@@ -65,13 +65,22 @@ _GLOBAL(flush_dcache_L1)
> >
> > blr
> >
> >+#define PVR_E6500 0x8040
> >+
> > /* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
> > _GLOBAL(__flush_disable_L1)
> >+/* L1 Data Cache of e6500 contains no modified data, no flush is
> >required */
> >+ mfspr r3, SPRN_PVR
> >+ rlwinm r4, r3, 16, 0xffff
> >+ lis r5, 0
> >+ ori r5, r5, PVR_E6500@l
> >+ cmpw r4, r5
> >+ beq 2f
> > mflr r10
> > bl flush_dcache_L1 /* Flush L1 d-cache */
> > mtlr r10
> >
> >- msync
> >+2: msync
> > mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
> > li r5, 2
> > rlwimi r4, r5, 0, 3
>
> Note that disabling the cache is a core operation, rather than a
> thread operation. Is this only called when the second thread is
> disabled?
>
> -Scott

It is called only when a core is down.
I can add a comment in the code.

-Chenhui

2013-04-24 11:30:21

by Chenhui Zhao

[permalink] [raw]
Subject: Re: [PATCH v2 12/15] powerpc/85xx: add time base sync support for e6500

On Tue, Apr 23, 2013 at 07:04:06PM -0500, Scott Wood wrote:
> On 04/19/2013 05:47:45 AM, Zhao Chenhui wrote:
> >From: Chen-Hui Zhao <[email protected]>
> >
> >For e6500, two threads in one core share one time base. Just need
> >to do time base sync on first thread of one core, and skip it on
> >the other thread.
> >
> >Signed-off-by: Zhao Chenhui <[email protected]>
> >Signed-off-by: Li Yang <[email protected]>
> >Signed-off-by: Andy Fleming <[email protected]>
> >---
> > arch/powerpc/platforms/85xx/smp.c | 52
> >+++++++++++++++++++++++++++++++-----
> > 1 files changed, 44 insertions(+), 8 deletions(-)
> >
> >diff --git a/arch/powerpc/platforms/85xx/smp.c
> >b/arch/powerpc/platforms/85xx/smp.c
> >index 74d8cde..5f3eee3 100644
> >--- a/arch/powerpc/platforms/85xx/smp.c
> >+++ b/arch/powerpc/platforms/85xx/smp.c
> >@@ -26,6 +26,7 @@
> > #include <asm/cacheflush.h>
> > #include <asm/dbell.h>
> > #include <asm/fsl_guts.h>
> >+#include <asm/cputhreads.h>
> >
> > #include <sysdev/fsl_soc.h>
> > #include <sysdev/mpic.h>
> >@@ -45,6 +46,7 @@ static u64 timebase;
> > static int tb_req;
> > static int tb_valid;
> > static u32 cur_booting_core;
> >+static bool rcpmv2;
> >
> > #ifdef CONFIG_PPC_E500MC
> > /* get a physical mask of online cores and booting core */
> >@@ -53,26 +55,40 @@ static inline u32 get_phy_cpu_mask(void)
> > u32 mask;
> > int cpu;
> >
> >- mask = 1 << cur_booting_core;
> >- for_each_online_cpu(cpu)
> >- mask |= 1 << get_hard_smp_processor_id(cpu);
> >+ if (smt_capable()) {
> >+ /* two threads in one core share one time base */
> >+ mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> >+ for_each_online_cpu(cpu)
> >+ mask |= 1 << cpu_core_index_of_thread(
> >+ get_hard_smp_processor_id(cpu));
> >+ } else {
> >+ mask = 1 << cur_booting_core;
> >+ for_each_online_cpu(cpu)
> >+ mask |= 1 << get_hard_smp_processor_id(cpu);
> >+ }
>
> Where is smt_capable defined()? I assume somewhere in the patchset
> but it's a pain to search 12 patches...
>

It is defined in arch/powerpc/include/asm/topology.h.
#define smt_capable() (cpu_has_feature(CPU_FTR_SMT))

Thanks for your review again.

> Is this really about whether we're SMT-capable or whether we have
> rcpm v2?
>
> -Scott

I think this "if" statement can be removed. The cpu_core_index_of_thread()
can return the correct cpu number with thread or without thread.

Like this:
static inline u32 get_phy_cpu_mask(void)
{
u32 mask;
int cpu;

mask = 1 << cpu_core_index_of_thread(cur_booting_core);
for_each_online_cpu(cpu)
mask |= 1 << cpu_core_index_of_thread(
get_hard_smp_processor_id(cpu));

return mask;
}

-Chenhui

2013-04-24 22:38:27

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 12/15] powerpc/85xx: add time base sync support for e6500

On 04/24/2013 06:29:29 AM, Zhao Chenhui wrote:
> On Tue, Apr 23, 2013 at 07:04:06PM -0500, Scott Wood wrote:
> > On 04/19/2013 05:47:45 AM, Zhao Chenhui wrote:
> > >From: Chen-Hui Zhao <[email protected]>
> > >
> > >For e6500, two threads in one core share one time base. Just need
> > >to do time base sync on first thread of one core, and skip it on
> > >the other thread.
> > >
> > >Signed-off-by: Zhao Chenhui <[email protected]>
> > >Signed-off-by: Li Yang <[email protected]>
> > >Signed-off-by: Andy Fleming <[email protected]>
> > >---
> > > arch/powerpc/platforms/85xx/smp.c | 52
> > >+++++++++++++++++++++++++++++++-----
> > > 1 files changed, 44 insertions(+), 8 deletions(-)
> > >
> > >diff --git a/arch/powerpc/platforms/85xx/smp.c
> > >b/arch/powerpc/platforms/85xx/smp.c
> > >index 74d8cde..5f3eee3 100644
> > >--- a/arch/powerpc/platforms/85xx/smp.c
> > >+++ b/arch/powerpc/platforms/85xx/smp.c
> > >@@ -26,6 +26,7 @@
> > > #include <asm/cacheflush.h>
> > > #include <asm/dbell.h>
> > > #include <asm/fsl_guts.h>
> > >+#include <asm/cputhreads.h>
> > >
> > > #include <sysdev/fsl_soc.h>
> > > #include <sysdev/mpic.h>
> > >@@ -45,6 +46,7 @@ static u64 timebase;
> > > static int tb_req;
> > > static int tb_valid;
> > > static u32 cur_booting_core;
> > >+static bool rcpmv2;
> > >
> > > #ifdef CONFIG_PPC_E500MC
> > > /* get a physical mask of online cores and booting core */
> > >@@ -53,26 +55,40 @@ static inline u32 get_phy_cpu_mask(void)
> > > u32 mask;
> > > int cpu;
> > >
> > >- mask = 1 << cur_booting_core;
> > >- for_each_online_cpu(cpu)
> > >- mask |= 1 << get_hard_smp_processor_id(cpu);
> > >+ if (smt_capable()) {
> > >+ /* two threads in one core share one time base */
> > >+ mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> > >+ for_each_online_cpu(cpu)
> > >+ mask |= 1 << cpu_core_index_of_thread(
> > >+ get_hard_smp_processor_id(cpu));
> > >+ } else {
> > >+ mask = 1 << cur_booting_core;
> > >+ for_each_online_cpu(cpu)
> > >+ mask |= 1 << get_hard_smp_processor_id(cpu);
> > >+ }
> >
> > Where is smt_capable defined()? I assume somewhere in the patchset
> > but it's a pain to search 12 patches...
> >
>
> It is defined in arch/powerpc/include/asm/topology.h.
> #define smt_capable() (cpu_has_feature(CPU_FTR_SMT))
>
> Thanks for your review again.

We shouldn't base it on CPU_FTR_SMT. For example, e6500 doesn't claim
that feature yet, except in our SDK kernel. That doesn't change the
topology of CPU numbering.

> > Is this really about whether we're SMT-capable or whether we have
> > rcpm v2?
> >
> > -Scott
>
> I think this "if" statement can be removed. The
> cpu_core_index_of_thread()
> can return the correct cpu number with thread or without thread.
>
> Like this:
> static inline u32 get_phy_cpu_mask(void)
> {
> u32 mask;
> int cpu;
>
> mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> for_each_online_cpu(cpu)
> mask |= 1 << cpu_core_index_of_thread(
> get_hard_smp_processor_id(cpu));
>
> return mask;
> }

Likewise, this will get it wrong if SMT is disabled or not yet
implemented on a core.

-Scott

2013-04-25 00:29:06

by Chenhui Zhao

[permalink] [raw]
Subject: Re: [PATCH v2 12/15] powerpc/85xx: add time base sync support for e6500

On Wed, Apr 24, 2013 at 05:38:16PM -0500, Scott Wood wrote:
> On 04/24/2013 06:29:29 AM, Zhao Chenhui wrote:
> >On Tue, Apr 23, 2013 at 07:04:06PM -0500, Scott Wood wrote:
> >> On 04/19/2013 05:47:45 AM, Zhao Chenhui wrote:
> >> >From: Chen-Hui Zhao <[email protected]>
> >> >
> >> >For e6500, two threads in one core share one time base. Just need
> >> >to do time base sync on first thread of one core, and skip it on
> >> >the other thread.
> >> >
> >> >Signed-off-by: Zhao Chenhui <[email protected]>
> >> >Signed-off-by: Li Yang <[email protected]>
> >> >Signed-off-by: Andy Fleming <[email protected]>
> >> >---
> >> > arch/powerpc/platforms/85xx/smp.c | 52
> >> >+++++++++++++++++++++++++++++++-----
> >> > 1 files changed, 44 insertions(+), 8 deletions(-)
> >> >
> >> >diff --git a/arch/powerpc/platforms/85xx/smp.c
> >> >b/arch/powerpc/platforms/85xx/smp.c
> >> >index 74d8cde..5f3eee3 100644
> >> >--- a/arch/powerpc/platforms/85xx/smp.c
> >> >+++ b/arch/powerpc/platforms/85xx/smp.c
> >> >@@ -53,26 +55,40 @@ static inline u32 get_phy_cpu_mask(void)
> >> > u32 mask;
> >> > int cpu;
> >> >
> >> >- mask = 1 << cur_booting_core;
> >> >- for_each_online_cpu(cpu)
> >> >- mask |= 1 << get_hard_smp_processor_id(cpu);
> >> >+ if (smt_capable()) {
> >> >+ /* two threads in one core share one time base */
> >> >+ mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> >> >+ for_each_online_cpu(cpu)
> >> >+ mask |= 1 << cpu_core_index_of_thread(
> >> >+ get_hard_smp_processor_id(cpu));
> >> >+ } else {
> >> >+ mask = 1 << cur_booting_core;
> >> >+ for_each_online_cpu(cpu)
> >> >+ mask |= 1 << get_hard_smp_processor_id(cpu);
> >> >+ }
> >>
> >> Where is smt_capable defined()? I assume somewhere in the patchset
> >> but it's a pain to search 12 patches...
> >>
> >
> >It is defined in arch/powerpc/include/asm/topology.h.
> > #define smt_capable() (cpu_has_feature(CPU_FTR_SMT))
> >
> >Thanks for your review again.
>
> We shouldn't base it on CPU_FTR_SMT. For example, e6500 doesn't
> claim that feature yet, except in our SDK kernel. That doesn't
> change the topology of CPU numbering.
>

Then, where can I get the thread information? dts?
Or, wait for upstream of the thread suppport of e6500.

> >> Is this really about whether we're SMT-capable or whether we have
> >> rcpm v2?
> >>
> >> -Scott
> >
> >I think this "if" statement can be removed. The
> >cpu_core_index_of_thread()
> >can return the correct cpu number with thread or without thread.
> >
> >Like this:
> >static inline u32 get_phy_cpu_mask(void)
> >{
> > u32 mask;
> > int cpu;
> >
> > mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> > for_each_online_cpu(cpu)
> > mask |= 1 << cpu_core_index_of_thread(
> > get_hard_smp_processor_id(cpu));
> >
> > return mask;
> >}
>
> Likewise, this will get it wrong if SMT is disabled or not yet
> implemented on a core.
>
> -Scott

Let's look into cpu_core_index_of_thread() in arch/powerpc/kernel/smp.c.

int cpu_core_index_of_thread(int cpu)
{
return cpu >> threads_shift;
}

If no thread, the threads_shift is equal to 0. It can work with no
thread.

Perhaps, I should submit this patch after the thread patches for e6500.

-Chenhui

2013-04-26 00:07:34

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 12/15] powerpc/85xx: add time base sync support for e6500

On 04/24/2013 07:28:18 PM, Zhao Chenhui wrote:
> On Wed, Apr 24, 2013 at 05:38:16PM -0500, Scott Wood wrote:
> > On 04/24/2013 06:29:29 AM, Zhao Chenhui wrote:
> > >On Tue, Apr 23, 2013 at 07:04:06PM -0500, Scott Wood wrote:
> > >> On 04/19/2013 05:47:45 AM, Zhao Chenhui wrote:
> > >> >From: Chen-Hui Zhao <[email protected]>
> > >> >
> > >> >For e6500, two threads in one core share one time base. Just
> need
> > >> >to do time base sync on first thread of one core, and skip it on
> > >> >the other thread.
> > >> >
> > >> >Signed-off-by: Zhao Chenhui <[email protected]>
> > >> >Signed-off-by: Li Yang <[email protected]>
> > >> >Signed-off-by: Andy Fleming <[email protected]>
> > >> >---
> > >> > arch/powerpc/platforms/85xx/smp.c | 52
> > >> >+++++++++++++++++++++++++++++++-----
> > >> > 1 files changed, 44 insertions(+), 8 deletions(-)
> > >> >
> > >> >diff --git a/arch/powerpc/platforms/85xx/smp.c
> > >> >b/arch/powerpc/platforms/85xx/smp.c
> > >> >index 74d8cde..5f3eee3 100644
> > >> >--- a/arch/powerpc/platforms/85xx/smp.c
> > >> >+++ b/arch/powerpc/platforms/85xx/smp.c
> > >> >@@ -53,26 +55,40 @@ static inline u32 get_phy_cpu_mask(void)
> > >> > u32 mask;
> > >> > int cpu;
> > >> >
> > >> >- mask = 1 << cur_booting_core;
> > >> >- for_each_online_cpu(cpu)
> > >> >- mask |= 1 << get_hard_smp_processor_id(cpu);
> > >> >+ if (smt_capable()) {
> > >> >+ /* two threads in one core share one time base
> */
> > >> >+ mask = 1 <<
> cpu_core_index_of_thread(cur_booting_core);
> > >> >+ for_each_online_cpu(cpu)
> > >> >+ mask |= 1 << cpu_core_index_of_thread(
> > >> >+
> get_hard_smp_processor_id(cpu));
> > >> >+ } else {
> > >> >+ mask = 1 << cur_booting_core;
> > >> >+ for_each_online_cpu(cpu)
> > >> >+ mask |= 1 <<
> get_hard_smp_processor_id(cpu);
> > >> >+ }
> > >>
> > >> Where is smt_capable defined()? I assume somewhere in the
> patchset
> > >> but it's a pain to search 12 patches...
> > >>
> > >
> > >It is defined in arch/powerpc/include/asm/topology.h.
> > > #define smt_capable() (cpu_has_feature(CPU_FTR_SMT))
> > >
> > >Thanks for your review again.
> >
> > We shouldn't base it on CPU_FTR_SMT. For example, e6500 doesn't
> > claim that feature yet, except in our SDK kernel. That doesn't
> > change the topology of CPU numbering.
> >
>
> Then, where can I get the thread information? dts?
> Or, wait for upstream of the thread suppport of e6500.

It's an inherent property of e6500 (outside of some virtualization
scenarios, but you wouldn't run this code under a hypervisor) that you
have two threads per core (whether Linux uses them or not). Or you
could read TMCFG0[NTHRD] if you know you're on a chip that has TMRs but
aren't positive it's an e6500, but I wouldn't bother. If we do ever
have such a chip, there are probably other things that will need
updating.

> > >static inline u32 get_phy_cpu_mask(void)
> > >{
> > > u32 mask;
> > > int cpu;
> > >
> > > mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> > > for_each_online_cpu(cpu)
> > > mask |= 1 << cpu_core_index_of_thread(
> > > get_hard_smp_processor_id(cpu));
> > >
> > > return mask;
> > >}
> >
> > Likewise, this will get it wrong if SMT is disabled or not yet
> > implemented on a core.
> >
> > -Scott
>
> Let's look into cpu_core_index_of_thread() in
> arch/powerpc/kernel/smp.c.
>
> int cpu_core_index_of_thread(int cpu)
> {
> return cpu >> threads_shift;
> }
>
> If no thread, the threads_shift is equal to 0. It can work with no
> thread.

My point is that if threads are disabled, threads_shift will be 0, but
e6500 cores will still be numbered 0, 2, 4, etc.

> Perhaps, I should submit this patch after the thread patches for
> e6500.

Why?

-Scott

2013-04-28 09:57:18

by Chenhui Zhao

[permalink] [raw]
Subject: Re: [PATCH v2 12/15] powerpc/85xx: add time base sync support for e6500

On Thu, Apr 25, 2013 at 07:07:24PM -0500, Scott Wood wrote:
> On 04/24/2013 07:28:18 PM, Zhao Chenhui wrote:
> >On Wed, Apr 24, 2013 at 05:38:16PM -0500, Scott Wood wrote:
> >> On 04/24/2013 06:29:29 AM, Zhao Chenhui wrote:
> >> >On Tue, Apr 23, 2013 at 07:04:06PM -0500, Scott Wood wrote:
> >> >> On 04/19/2013 05:47:45 AM, Zhao Chenhui wrote:
> >> >> >From: Chen-Hui Zhao <[email protected]>
> >> >> >
> >> >> >For e6500, two threads in one core share one time base. Just
> >need
> >> >> >to do time base sync on first thread of one core, and skip it on
> >> >> >the other thread.
> >> >> >
> >> >> >Signed-off-by: Zhao Chenhui <[email protected]>
> >> >> >Signed-off-by: Li Yang <[email protected]>
> >> >> >Signed-off-by: Andy Fleming <[email protected]>
> >> >> >---
> >> >> > arch/powerpc/platforms/85xx/smp.c | 52
> >> >> >+++++++++++++++++++++++++++++++-----
> >> >> > 1 files changed, 44 insertions(+), 8 deletions(-)
> >> >> >
> >> >> >diff --git a/arch/powerpc/platforms/85xx/smp.c
> >> >> >b/arch/powerpc/platforms/85xx/smp.c
> >> >> >index 74d8cde..5f3eee3 100644
> >> >> >--- a/arch/powerpc/platforms/85xx/smp.c
> >> >> >+++ b/arch/powerpc/platforms/85xx/smp.c
> >> >> >@@ -53,26 +55,40 @@ static inline u32 get_phy_cpu_mask(void)
> >> >> > u32 mask;
> >> >> > int cpu;
> >> >> >
> >> >> >- mask = 1 << cur_booting_core;
> >> >> >- for_each_online_cpu(cpu)
> >> >> >- mask |= 1 << get_hard_smp_processor_id(cpu);
> >> >> >+ if (smt_capable()) {
> >> >> >+ /* two threads in one core share one time base */
> >> >> >+ mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> >> >> >+ for_each_online_cpu(cpu)
> >> >> >+ mask |= 1 << cpu_core_index_of_thread(
> >> >> >+ get_hard_smp_processor_id(cpu));
> >> >> >+ } else {
> >> >> >+ mask = 1 << cur_booting_core;
> >> >> >+ for_each_online_cpu(cpu)
> >> >> >+ mask |= 1 << get_hard_smp_processor_id(cpu);
> >> >> >+ }
> >> >>
> >> >> Where is smt_capable defined()? I assume somewhere in the
> >patchset
> >> >> but it's a pain to search 12 patches...
> >> >>
> >> >
> >> >It is defined in arch/powerpc/include/asm/topology.h.
> >> > #define smt_capable() (cpu_has_feature(CPU_FTR_SMT))
> >> >
> >> >Thanks for your review again.
> >>
> >> We shouldn't base it on CPU_FTR_SMT. For example, e6500 doesn't
> >> claim that feature yet, except in our SDK kernel. That doesn't
> >> change the topology of CPU numbering.
> >>
> >
> >Then, where can I get the thread information? dts?
> >Or, wait for upstream of the thread suppport of e6500.
>
> It's an inherent property of e6500 (outside of some virtualization
> scenarios, but you wouldn't run this code under a hypervisor) that
> you have two threads per core (whether Linux uses them or not). Or
> you could read TMCFG0[NTHRD] if you know you're on a chip that has
> TMRs but aren't positive it's an e6500, but I wouldn't bother. If
> we do ever have such a chip, there are probably other things that
> will need updating.
>

But how to know that there are TMRs on a chip except by CPU_FTR_SMT.

> >> >static inline u32 get_phy_cpu_mask(void)
> >> >{
> >> > u32 mask;
> >> > int cpu;
> >> >
> >> > mask = 1 << cpu_core_index_of_thread(cur_booting_core);
> >> > for_each_online_cpu(cpu)
> >> > mask |= 1 << cpu_core_index_of_thread(
> >> > get_hard_smp_processor_id(cpu));
> >> >
> >> > return mask;
> >> >}
> >>
> >> Likewise, this will get it wrong if SMT is disabled or not yet
> >> implemented on a core.
> >>
> >> -Scott
> >
> >Let's look into cpu_core_index_of_thread() in
> >arch/powerpc/kernel/smp.c.
> >
> > int cpu_core_index_of_thread(int cpu)
> > {
> > return cpu >> threads_shift;
> > }
> >
> >If no thread, the threads_shift is equal to 0. It can work with no
> >thread.
>
> My point is that if threads are disabled, threads_shift will be 0,
> but e6500 cores will still be numbered 0, 2, 4, etc.
>
> >Perhaps, I should submit this patch after the thread patches for
> >e6500.
>
> Why?
>
> -Scott

Even if threads are disabled, the threads_shift derived from dts is right.
But, if there aren't the thread related patches existed in SDK, the threads_shift
gets a wrong value on T4.

-Chenhui

2013-04-28 10:21:22

by Chenhui Zhao

[permalink] [raw]
Subject: Re: [PATCH v2 02/15] powerpc/85xx: add sleep and deep sleep support

On Tue, Apr 23, 2013 at 06:53:20PM -0500, Scott Wood wrote:
> On 04/19/2013 05:47:35 AM, Zhao Chenhui wrote:
> > static int pmc_suspend_enter(suspend_state_t state)
> > {
> >- int ret;
> >+ int ret = 0;
> >+
> >+ switch (state) {
> >+#ifdef CONFIG_PPC_85xx
> >+ case PM_SUSPEND_MEM:
> >+#ifdef CONFIG_SPE
> >+ enable_kernel_spe();
> >+#endif
> >+ enable_kernel_fp();
>
> Why does enable_kernel_spe() need an ifdef but enable_kernel_fp()
> doesn't?
>

will enclose it with CONFIG_PPC_FPU.

> >+ case PM_SUSPEND_STANDBY:
> >+#ifdef CONFIG_FSL_SOC_BOOKE
> >+ flush_dcache_L1();
> >+#endif
> >+ setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_SLP);
>
> Only L1, even on e500mc?
>
> -Scott

This patch is just for chips with pmc unit. They have no e500mc core.

-Chenhui

2013-04-29 20:19:06

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 12/15] powerpc/85xx: add time base sync support for e6500

On 04/28/2013 04:56:34 AM, Zhao Chenhui wrote:
> On Thu, Apr 25, 2013 at 07:07:24PM -0500, Scott Wood wrote:
> > On 04/24/2013 07:28:18 PM, Zhao Chenhui wrote:
> > >On Wed, Apr 24, 2013 at 05:38:16PM -0500, Scott Wood wrote:
> > >> We shouldn't base it on CPU_FTR_SMT. For example, e6500 doesn't
> > >> claim that feature yet, except in our SDK kernel. That doesn't
> > >> change the topology of CPU numbering.
> > >>
> > >
> > >Then, where can I get the thread information? dts?
> > >Or, wait for upstream of the thread suppport of e6500.
> >
> > It's an inherent property of e6500 (outside of some virtualization
> > scenarios, but you wouldn't run this code under a hypervisor) that
> > you have two threads per core (whether Linux uses them or not). Or
> > you could read TMCFG0[NTHRD] if you know you're on a chip that has
> > TMRs but aren't positive it's an e6500, but I wouldn't bother. If
> > we do ever have such a chip, there are probably other things that
> > will need updating.
> >
>
> But how to know that there are TMRs on a chip except by CPU_FTR_SMT.

I don't know. I said I wouldn't bother. :-)

Just assume there are 2 threads per core on e6500. Then you won't have
a dependency on the threading patches, and you won't break if
CPU_FTR_SMT gets disabled for some other reason, or if the threads are
missing from the device tree for some reason (I've seen some people
remove them manually in an attempt to disable threading -- I tell them
not to when I see it, but eventually others will do it again).

-Scott

2013-06-03 22:43:21

by Scott Wood

[permalink] [raw]
Subject: Re: [PATCH v2 05/15] fsl_pmc: update device bindings

On 04/19/2013 05:47:38 AM, Zhao Chenhui wrote:
> From: Li Yang <[email protected]>
>
> Signed-off-by: Li Yang <[email protected]>
> Signed-off-by: Zhao Chenhui <[email protected]>
> ---
> .../devicetree/bindings/powerpc/fsl/pmc.txt | 59
> +++++++++++--------
> 1 files changed, 34 insertions(+), 25 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
> b/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
> index 07256b7..f1f749f 100644
> --- a/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
> +++ b/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
> @@ -9,15 +9,20 @@ Properties:
>
> "fsl,mpc8548-pmc" should be listed for any chip whose PMC is
> compatible. "fsl,mpc8536-pmc" should also be listed for any chip
> - whose PMC is compatible, and implies deep-sleep capability.
> + whose PMC is compatible, and implies deep-sleep capability and
> + wake on user defined packet(wakeup on ARP).
> +
> + "fsl,p1022-pmc" should be listed for any chip whose PMC is
> + compatible, and implies lossless Ethernet capability during sleep.
>
> "fsl,mpc8641d-pmc" should be listed for any chip whose PMC is
> compatible; all statements below that apply to "fsl,mpc8548-pmc"
> also
> apply to "fsl,mpc8641d-pmc".
>
> Compatibility does not include bit assignments in
> SCCR/PMCDR/DEVDISR; these
> - bit assignments are indicated via the sleep specifier in each
> device's
> - sleep property.
> + bit assignments are indicated via the clock nodes. Device which
> has a
> + controllable clock source should have a "fsl,pmc-handle" property
> pointing
> + to the clock node.

Please respond to the feedback given on v1:
http://patchwork.ozlabs.org/patch/147177/

Also indicate, below the ---, what has changed from previous versions.

-Scott