Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Zhao Chenhui and committed by
Kumar Gala
bf345263 ae5cab47

+84
+2
arch/powerpc/include/asm/fsl_guts.h
··· 48 48 __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */ 49 49 u8 res06c[0x70 - 0x6c]; 50 50 __be32 devdisr; /* 0x.0070 - Device Disable Control */ 51 + #define CCSR_GUTS_DEVDISR_TB1 0x00001000 52 + #define CCSR_GUTS_DEVDISR_TB0 0x00004000 51 53 __be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */ 52 54 u8 res078[0x7c - 0x78]; 53 55 __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */
+82
arch/powerpc/platforms/85xx/smp.c
··· 25 25 #include <asm/mpic.h> 26 26 #include <asm/cacheflush.h> 27 27 #include <asm/dbell.h> 28 + #include <asm/fsl_guts.h> 28 29 29 30 #include <sysdev/fsl_soc.h> 30 31 #include <sysdev/mpic.h> ··· 41 40 u32 reserved; 42 41 u32 pir; 43 42 }; 43 + 44 + static struct ccsr_guts __iomem *guts; 45 + static u64 timebase; 46 + static int tb_req; 47 + static int tb_valid; 48 + 49 + static void mpc85xx_timebase_freeze(int freeze) 50 + { 51 + uint32_t mask; 52 + 53 + mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1; 54 + if (freeze) 55 + setbits32(&guts->devdisr, mask); 56 + else 57 + clrbits32(&guts->devdisr, mask); 58 + 59 + in_be32(&guts->devdisr); 60 + } 61 + 62 + static void mpc85xx_give_timebase(void) 63 + { 64 + unsigned long flags; 65 + 66 + local_irq_save(flags); 67 + 68 + while (!tb_req) 69 + barrier(); 70 + tb_req = 0; 71 + 72 + mpc85xx_timebase_freeze(1); 73 + timebase = get_tb(); 74 + mb(); 75 + tb_valid = 1; 76 + 77 + while (tb_valid) 78 + barrier(); 79 + 80 + mpc85xx_timebase_freeze(0); 81 + 82 + local_irq_restore(flags); 83 + } 84 + 85 + static void mpc85xx_take_timebase(void) 86 + { 87 + unsigned long flags; 88 + 89 + local_irq_save(flags); 90 + 91 + tb_req = 1; 92 + while (!tb_valid) 93 + barrier(); 94 + 95 + set_tb(timebase >> 32, timebase & 0xffffffff); 96 + isync(); 97 + tb_valid = 0; 98 + 99 + local_irq_restore(flags); 100 + } 44 101 45 102 static int __init 46 103 smp_85xx_kick_cpu(int nr) ··· 287 228 doorbell_setup_this_cpu(); 288 229 } 289 230 231 + static const struct of_device_id mpc85xx_smp_guts_ids[] = { 232 + { .compatible = "fsl,mpc8572-guts", }, 233 + { .compatible = "fsl,p1020-guts", }, 234 + { .compatible = "fsl,p1021-guts", }, 235 + { .compatible = "fsl,p1022-guts", }, 236 + { .compatible = "fsl,p1023-guts", }, 237 + { .compatible = "fsl,p2020-guts", }, 238 + {}, 239 + }; 240 + 290 241 void __init mpc85xx_smp_init(void) 291 242 { 292 243 struct device_node *np; ··· 316 247 */ 317 248 smp_85xx_ops.message_pass = NULL; 318 249 smp_85xx_ops.cause_ipi = doorbell_cause_ipi; 250 + } 251 + 252 + np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); 253 + if (np) { 254 + guts = of_iomap(np, 0); 255 + of_node_put(np); 256 + if (!guts) { 257 + pr_err("%s: Could not map guts node address\n", 258 + __func__); 259 + return; 260 + } 261 + smp_85xx_ops.give_timebase = mpc85xx_give_timebase; 262 + smp_85xx_ops.take_timebase = mpc85xx_take_timebase; 319 263 } 320 264 321 265 smp_ops = &smp_85xx_ops;