aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhao Chenhui <chenhui.zhao@freescale.com>2012-07-20 08:42:35 -0400
committerKumar Gala <galak@kernel.crashing.org>2012-09-12 15:57:08 -0400
commitbf34526374a334ddfafaed73b0d8bf7eb4dea833 (patch)
tree409a950552f72205381e9ecad3bb8cd02d5f4b93
parentae5cab476342bc7311945cf89d5cbd8d57f4a5a9 (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.h2
-rw-r--r--arch/powerpc/platforms/85xx/smp.c82
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
45static struct ccsr_guts __iomem *guts;
46static u64 timebase;
47static int tb_req;
48static int tb_valid;
49
50static 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
63static 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
86static 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
44static int __init 103static int __init
45smp_85xx_kick_cpu(int nr) 104smp_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
290static 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
231void __init mpc85xx_smp_init(void) 300void __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