diff options
author | Zhao Chenhui <chenhui.zhao@freescale.com> | 2012-07-20 08:42:35 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2012-09-12 15:57:08 -0400 |
commit | bf34526374a334ddfafaed73b0d8bf7eb4dea833 (patch) | |
tree | 409a950552f72205381e9ecad3bb8cd02d5f4b93 | |
parent | ae5cab476342bc7311945cf89d5cbd8d57f4a5a9 (diff) |
powerpc/85xx: implement hardware timebase sync
Do hardware timebase sync. Firstly, stop all timebases, and transfer the
timebase value of the boot core to the other core. Finally, start all
timebases.
Only apply to dual-core chips, such as MPC8572, P2020, etc.
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/include/asm/fsl_guts.h | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/smp.c | 82 |
2 files changed, 84 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index aa4c488589ce..dd5ba2c22771 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h | |||
@@ -48,6 +48,8 @@ struct ccsr_guts { | |||
48 | __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */ | 48 | __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */ |
49 | u8 res06c[0x70 - 0x6c]; | 49 | u8 res06c[0x70 - 0x6c]; |
50 | __be32 devdisr; /* 0x.0070 - Device Disable Control */ | 50 | __be32 devdisr; /* 0x.0070 - Device Disable Control */ |
51 | #define CCSR_GUTS_DEVDISR_TB1 0x00001000 | ||
52 | #define CCSR_GUTS_DEVDISR_TB0 0x00004000 | ||
51 | __be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */ | 53 | __be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */ |
52 | u8 res078[0x7c - 0x78]; | 54 | u8 res078[0x7c - 0x78]; |
53 | __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */ | 55 | __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */ |
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 4827709996ce..7ed52a604a13 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <asm/mpic.h> | 25 | #include <asm/mpic.h> |
26 | #include <asm/cacheflush.h> | 26 | #include <asm/cacheflush.h> |
27 | #include <asm/dbell.h> | 27 | #include <asm/dbell.h> |
28 | #include <asm/fsl_guts.h> | ||
28 | 29 | ||
29 | #include <sysdev/fsl_soc.h> | 30 | #include <sysdev/fsl_soc.h> |
30 | #include <sysdev/mpic.h> | 31 | #include <sysdev/mpic.h> |
@@ -41,6 +42,64 @@ struct epapr_spin_table { | |||
41 | u32 pir; | 42 | u32 pir; |
42 | }; | 43 | }; |
43 | 44 | ||
45 | static struct ccsr_guts __iomem *guts; | ||
46 | static u64 timebase; | ||
47 | static int tb_req; | ||
48 | static int tb_valid; | ||
49 | |||
50 | static void mpc85xx_timebase_freeze(int freeze) | ||
51 | { | ||
52 | uint32_t mask; | ||
53 | |||
54 | mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1; | ||
55 | if (freeze) | ||
56 | setbits32(&guts->devdisr, mask); | ||
57 | else | ||
58 | clrbits32(&guts->devdisr, mask); | ||
59 | |||
60 | in_be32(&guts->devdisr); | ||
61 | } | ||
62 | |||
63 | static void mpc85xx_give_timebase(void) | ||
64 | { | ||
65 | unsigned long flags; | ||
66 | |||
67 | local_irq_save(flags); | ||
68 | |||
69 | while (!tb_req) | ||
70 | barrier(); | ||
71 | tb_req = 0; | ||
72 | |||
73 | mpc85xx_timebase_freeze(1); | ||
74 | timebase = get_tb(); | ||
75 | mb(); | ||
76 | tb_valid = 1; | ||
77 | |||
78 | while (tb_valid) | ||
79 | barrier(); | ||
80 | |||
81 | mpc85xx_timebase_freeze(0); | ||
82 | |||
83 | local_irq_restore(flags); | ||
84 | } | ||
85 | |||
86 | static void mpc85xx_take_timebase(void) | ||
87 | { | ||
88 | unsigned long flags; | ||
89 | |||
90 | local_irq_save(flags); | ||
91 | |||
92 | tb_req = 1; | ||
93 | while (!tb_valid) | ||
94 | barrier(); | ||
95 | |||
96 | set_tb(timebase >> 32, timebase & 0xffffffff); | ||
97 | isync(); | ||
98 | tb_valid = 0; | ||
99 | |||
100 | local_irq_restore(flags); | ||
101 | } | ||
102 | |||
44 | static int __init | 103 | static int __init |
45 | smp_85xx_kick_cpu(int nr) | 104 | smp_85xx_kick_cpu(int nr) |
46 | { | 105 | { |
@@ -228,6 +287,16 @@ smp_85xx_setup_cpu(int cpu_nr) | |||
228 | doorbell_setup_this_cpu(); | 287 | doorbell_setup_this_cpu(); |
229 | } | 288 | } |
230 | 289 | ||
290 | static const struct of_device_id mpc85xx_smp_guts_ids[] = { | ||
291 | { .compatible = "fsl,mpc8572-guts", }, | ||
292 | { .compatible = "fsl,p1020-guts", }, | ||
293 | { .compatible = "fsl,p1021-guts", }, | ||
294 | { .compatible = "fsl,p1022-guts", }, | ||
295 | { .compatible = "fsl,p1023-guts", }, | ||
296 | { .compatible = "fsl,p2020-guts", }, | ||
297 | {}, | ||
298 | }; | ||
299 | |||
231 | void __init mpc85xx_smp_init(void) | 300 | void __init mpc85xx_smp_init(void) |
232 | { | 301 | { |
233 | struct device_node *np; | 302 | struct device_node *np; |
@@ -249,6 +318,19 @@ void __init mpc85xx_smp_init(void) | |||
249 | smp_85xx_ops.cause_ipi = doorbell_cause_ipi; | 318 | smp_85xx_ops.cause_ipi = doorbell_cause_ipi; |
250 | } | 319 | } |
251 | 320 | ||
321 | np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); | ||
322 | if (np) { | ||
323 | guts = of_iomap(np, 0); | ||
324 | of_node_put(np); | ||
325 | if (!guts) { | ||
326 | pr_err("%s: Could not map guts node address\n", | ||
327 | __func__); | ||
328 | return; | ||
329 | } | ||
330 | smp_85xx_ops.give_timebase = mpc85xx_give_timebase; | ||
331 | smp_85xx_ops.take_timebase = mpc85xx_take_timebase; | ||
332 | } | ||
333 | |||
252 | smp_ops = &smp_85xx_ops; | 334 | smp_ops = &smp_85xx_ops; |
253 | 335 | ||
254 | #ifdef CONFIG_KEXEC | 336 | #ifdef CONFIG_KEXEC |