diff options
author | Olof Johansson <olof@lixom.net> | 2013-01-28 02:03:42 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-01-28 02:03:42 -0500 |
commit | af70fdc947dbe835acc26c6ee9e8e930f38935f8 (patch) | |
tree | 9924e9f2732e3cf3c7a882cb11377247729891ab /arch/arm/mach-prima2 | |
parent | 66eae035dc59755c51ad3b3c718a5ed7535322e3 (diff) | |
parent | 7f46a10724e0d31c83029436e54298be2cc558fa (diff) |
Merge branch 'marco-timer-cleanup-rebase' of git://gitorious.org/sirfprima2-kernel/sirfprima2-kernel into next/soc
From Barry Song, this adds support for a new SoC from CSR; marco. It's
SMP, uses GIC instead of VIC and in general needs a bit of rework of
the platform code for setup, which this branch contains.
* 'marco-timer-cleanup-rebase' of git://gitorious.org/sirfprima2-kernel/sirfprima2-kernel:
ARM: PRIMA2: provide two DEBUG_LL ports for prima2 and marco
ARM: PRIMA2: add new SiRFmarco SMP SoC infrastructures
ARM: PRIMA2: irq: make prima2 irq can work even we enable GIC for Marco
ARM: PRIMA2: rtciobg: it is also compatible with marco
ARM: PRIMA2: rstc: enable the support for Marco
ARM: PRIMA2: mv timer to timer-prima2 as we will add timer-marco
ARM: PRIMA2: initialize l2x0 according to mach from DT
ARM: PRIMA2: enable AUTO_ZRELADDR for SIRF in Kconfig
ARM: PRIMA2: add CSR SiRFmarco device tree .dts
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-prima2')
-rw-r--r-- | arch/arm/mach-prima2/Kconfig | 10 | ||||
-rw-r--r-- | arch/arm/mach-prima2/Makefile | 5 | ||||
-rw-r--r-- | arch/arm/mach-prima2/common.c | 45 | ||||
-rw-r--r-- | arch/arm/mach-prima2/common.h | 15 | ||||
-rw-r--r-- | arch/arm/mach-prima2/headsmp.S | 79 | ||||
-rw-r--r-- | arch/arm/mach-prima2/hotplug.c | 41 | ||||
-rw-r--r-- | arch/arm/mach-prima2/include/mach/irqs.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-prima2/include/mach/uart.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-prima2/include/mach/uncompress.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-prima2/irq.c | 16 | ||||
-rw-r--r-- | arch/arm/mach-prima2/l2x0.c | 29 | ||||
-rw-r--r-- | arch/arm/mach-prima2/platsmp.c | 163 | ||||
-rw-r--r-- | arch/arm/mach-prima2/rstc.c | 45 | ||||
-rw-r--r-- | arch/arm/mach-prima2/rtciobrg.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-prima2/timer-marco.c | 316 | ||||
-rw-r--r-- | arch/arm/mach-prima2/timer-prima2.c (renamed from arch/arm/mach-prima2/timer.c) | 6 |
16 files changed, 751 insertions, 33 deletions
diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index 558ccfb8d458..4f7379fe01e2 100644 --- a/arch/arm/mach-prima2/Kconfig +++ b/arch/arm/mach-prima2/Kconfig | |||
@@ -11,6 +11,16 @@ config ARCH_PRIMA2 | |||
11 | help | 11 | help |
12 | Support for CSR SiRFSoC ARM Cortex A9 Platform | 12 | Support for CSR SiRFSoC ARM Cortex A9 Platform |
13 | 13 | ||
14 | config ARCH_MARCO | ||
15 | bool "CSR SiRFSoC MARCO ARM Cortex A9 Platform" | ||
16 | default y | ||
17 | select ARM_GIC | ||
18 | select CPU_V7 | ||
19 | select HAVE_SMP | ||
20 | select SMP_ON_UP | ||
21 | help | ||
22 | Support for CSR SiRFSoC ARM Cortex A9 Platform | ||
23 | |||
14 | endmenu | 24 | endmenu |
15 | 25 | ||
16 | config SIRF_IRQ | 26 | config SIRF_IRQ |
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile index fc9ce22e2b5a..bfe360cbd177 100644 --- a/arch/arm/mach-prima2/Makefile +++ b/arch/arm/mach-prima2/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | obj-y := timer.o | ||
2 | obj-y += rstc.o | 1 | obj-y += rstc.o |
3 | obj-y += common.o | 2 | obj-y += common.o |
4 | obj-y += rtciobrg.o | 3 | obj-y += rtciobrg.o |
@@ -6,3 +5,7 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o | |||
6 | obj-$(CONFIG_CACHE_L2X0) += l2x0.o | 5 | obj-$(CONFIG_CACHE_L2X0) += l2x0.o |
7 | obj-$(CONFIG_SUSPEND) += pm.o sleep.o | 6 | obj-$(CONFIG_SUSPEND) += pm.o sleep.o |
8 | obj-$(CONFIG_SIRF_IRQ) += irq.o | 7 | obj-$(CONFIG_SIRF_IRQ) += irq.o |
8 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | ||
9 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | ||
10 | obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o | ||
11 | obj-$(CONFIG_ARCH_MARCO) += timer-marco.o | ||
diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c index ed3570e5eb8f..00a65649a7e2 100644 --- a/arch/arm/mach-prima2/common.c +++ b/arch/arm/mach-prima2/common.c | |||
@@ -8,9 +8,11 @@ | |||
8 | 8 | ||
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/of_irq.h> | ||
11 | #include <asm/sizes.h> | 12 | #include <asm/sizes.h> |
12 | #include <asm/mach-types.h> | 13 | #include <asm/mach-types.h> |
13 | #include <asm/mach/arch.h> | 14 | #include <asm/mach/arch.h> |
15 | #include <asm/hardware/gic.h> | ||
14 | #include <linux/of.h> | 16 | #include <linux/of.h> |
15 | #include <linux/of_platform.h> | 17 | #include <linux/of_platform.h> |
16 | #include "common.h" | 18 | #include "common.h" |
@@ -30,6 +32,12 @@ void __init sirfsoc_init_late(void) | |||
30 | sirfsoc_pm_init(); | 32 | sirfsoc_pm_init(); |
31 | } | 33 | } |
32 | 34 | ||
35 | static __init void sirfsoc_map_io(void) | ||
36 | { | ||
37 | sirfsoc_map_lluart(); | ||
38 | sirfsoc_map_scu(); | ||
39 | } | ||
40 | |||
33 | #ifdef CONFIG_ARCH_PRIMA2 | 41 | #ifdef CONFIG_ARCH_PRIMA2 |
34 | static const char *prima2_dt_match[] __initdata = { | 42 | static const char *prima2_dt_match[] __initdata = { |
35 | "sirf,prima2", | 43 | "sirf,prima2", |
@@ -38,9 +46,12 @@ static const char *prima2_dt_match[] __initdata = { | |||
38 | 46 | ||
39 | DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") | 47 | DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") |
40 | /* Maintainer: Barry Song <baohua.song@csr.com> */ | 48 | /* Maintainer: Barry Song <baohua.song@csr.com> */ |
41 | .map_io = sirfsoc_map_lluart, | 49 | .map_io = sirfsoc_map_io, |
42 | .init_irq = sirfsoc_of_irq_init, | 50 | .init_irq = sirfsoc_of_irq_init, |
43 | .init_time = sirfsoc_timer_init, | 51 | .init_time = sirfsoc_prima2_timer_init, |
52 | #ifdef CONFIG_MULTI_IRQ_HANDLER | ||
53 | .handle_irq = sirfsoc_handle_irq, | ||
54 | #endif | ||
44 | .dma_zone_size = SZ_256M, | 55 | .dma_zone_size = SZ_256M, |
45 | .init_machine = sirfsoc_mach_init, | 56 | .init_machine = sirfsoc_mach_init, |
46 | .init_late = sirfsoc_init_late, | 57 | .init_late = sirfsoc_init_late, |
@@ -48,3 +59,33 @@ DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)") | |||
48 | .restart = sirfsoc_restart, | 59 | .restart = sirfsoc_restart, |
49 | MACHINE_END | 60 | MACHINE_END |
50 | #endif | 61 | #endif |
62 | |||
63 | #ifdef CONFIG_ARCH_MARCO | ||
64 | static const struct of_device_id marco_irq_match[] __initconst = { | ||
65 | { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, | ||
66 | { /* sentinel */ } | ||
67 | }; | ||
68 | |||
69 | static void __init marco_init_irq(void) | ||
70 | { | ||
71 | of_irq_init(marco_irq_match); | ||
72 | } | ||
73 | |||
74 | static const char *marco_dt_match[] __initdata = { | ||
75 | "sirf,marco", | ||
76 | NULL | ||
77 | }; | ||
78 | |||
79 | DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)") | ||
80 | /* Maintainer: Barry Song <baohua.song@csr.com> */ | ||
81 | .smp = smp_ops(sirfsoc_smp_ops), | ||
82 | .map_io = sirfsoc_map_io, | ||
83 | .init_irq = marco_init_irq, | ||
84 | .init_time = sirfsoc_marco_timer_init, | ||
85 | .handle_irq = gic_handle_irq, | ||
86 | .init_machine = sirfsoc_mach_init, | ||
87 | .init_late = sirfsoc_init_late, | ||
88 | .dt_compat = marco_dt_match, | ||
89 | .restart = sirfsoc_restart, | ||
90 | MACHINE_END | ||
91 | #endif | ||
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index 9c75f124e3cf..b7c26b62e4a7 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h | |||
@@ -11,12 +11,19 @@ | |||
11 | 11 | ||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <asm/mach/time.h> | 13 | #include <asm/mach/time.h> |
14 | #include <asm/exception.h> | ||
14 | 15 | ||
15 | extern void sirfsoc_timer_init(void); | 16 | extern void sirfsoc_prima2_timer_init(void); |
17 | extern void sirfsoc_marco_timer_init(void); | ||
18 | |||
19 | extern struct smp_operations sirfsoc_smp_ops; | ||
20 | extern void sirfsoc_secondary_startup(void); | ||
21 | extern void sirfsoc_cpu_die(unsigned int cpu); | ||
16 | 22 | ||
17 | extern void __init sirfsoc_of_irq_init(void); | 23 | extern void __init sirfsoc_of_irq_init(void); |
18 | extern void __init sirfsoc_of_clk_init(void); | 24 | extern void __init sirfsoc_of_clk_init(void); |
19 | extern void sirfsoc_restart(char, const char *); | 25 | extern void sirfsoc_restart(char, const char *); |
26 | extern asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs); | ||
20 | 27 | ||
21 | #ifndef CONFIG_DEBUG_LL | 28 | #ifndef CONFIG_DEBUG_LL |
22 | static inline void sirfsoc_map_lluart(void) {} | 29 | static inline void sirfsoc_map_lluart(void) {} |
@@ -24,6 +31,12 @@ static inline void sirfsoc_map_lluart(void) {} | |||
24 | extern void __init sirfsoc_map_lluart(void); | 31 | extern void __init sirfsoc_map_lluart(void); |
25 | #endif | 32 | #endif |
26 | 33 | ||
34 | #ifndef CONFIG_SMP | ||
35 | static inline void sirfsoc_map_scu(void) {} | ||
36 | #else | ||
37 | extern void sirfsoc_map_scu(void); | ||
38 | #endif | ||
39 | |||
27 | #ifdef CONFIG_SUSPEND | 40 | #ifdef CONFIG_SUSPEND |
28 | extern int sirfsoc_pm_init(void); | 41 | extern int sirfsoc_pm_init(void); |
29 | #else | 42 | #else |
diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S new file mode 100644 index 000000000000..6ec19d51a271 --- /dev/null +++ b/arch/arm/mach-prima2/headsmp.S | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * Entry of the second core for CSR Marco dual-core SMP SoCs | ||
3 | * | ||
4 | * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
5 | * | ||
6 | * Licensed under GPLv2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/linkage.h> | ||
10 | #include <linux/init.h> | ||
11 | |||
12 | __INIT | ||
13 | /* | ||
14 | * Cold boot and hardware reset show different behaviour, | ||
15 | * system will be always panic if we warm-reset the board | ||
16 | * Here we invalidate L1 of CPU1 to make sure there isn't | ||
17 | * uninitialized data written into memory later | ||
18 | */ | ||
19 | ENTRY(v7_invalidate_l1) | ||
20 | mov r0, #0 | ||
21 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
22 | mcr p15, 2, r0, c0, c0, 0 | ||
23 | mrc p15, 1, r0, c0, c0, 0 | ||
24 | |||
25 | ldr r1, =0x7fff | ||
26 | and r2, r1, r0, lsr #13 | ||
27 | |||
28 | ldr r1, =0x3ff | ||
29 | |||
30 | and r3, r1, r0, lsr #3 @ NumWays - 1 | ||
31 | add r2, r2, #1 @ NumSets | ||
32 | |||
33 | and r0, r0, #0x7 | ||
34 | add r0, r0, #4 @ SetShift | ||
35 | |||
36 | clz r1, r3 @ WayShift | ||
37 | add r4, r3, #1 @ NumWays | ||
38 | 1: sub r2, r2, #1 @ NumSets-- | ||
39 | mov r3, r4 @ Temp = NumWays | ||
40 | 2: subs r3, r3, #1 @ Temp-- | ||
41 | mov r5, r3, lsl r1 | ||
42 | mov r6, r2, lsl r0 | ||
43 | orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift) | ||
44 | mcr p15, 0, r5, c7, c6, 2 | ||
45 | bgt 2b | ||
46 | cmp r2, #0 | ||
47 | bgt 1b | ||
48 | dsb | ||
49 | isb | ||
50 | mov pc, lr | ||
51 | ENDPROC(v7_invalidate_l1) | ||
52 | |||
53 | /* | ||
54 | * SIRFSOC specific entry point for secondary CPUs. This provides | ||
55 | * a "holding pen" into which all secondary cores are held until we're | ||
56 | * ready for them to initialise. | ||
57 | */ | ||
58 | ENTRY(sirfsoc_secondary_startup) | ||
59 | bl v7_invalidate_l1 | ||
60 | mrc p15, 0, r0, c0, c0, 5 | ||
61 | and r0, r0, #15 | ||
62 | adr r4, 1f | ||
63 | ldmia r4, {r5, r6} | ||
64 | sub r4, r4, r5 | ||
65 | add r6, r6, r4 | ||
66 | pen: ldr r7, [r6] | ||
67 | cmp r7, r0 | ||
68 | bne pen | ||
69 | |||
70 | /* | ||
71 | * we've been released from the holding pen: secondary_stack | ||
72 | * should now contain the SVC stack for this core | ||
73 | */ | ||
74 | b secondary_startup | ||
75 | ENDPROC(sirfsoc_secondary_startup) | ||
76 | |||
77 | .align | ||
78 | 1: .long . | ||
79 | .long pen_release | ||
diff --git a/arch/arm/mach-prima2/hotplug.c b/arch/arm/mach-prima2/hotplug.c new file mode 100644 index 000000000000..97c1ee586442 --- /dev/null +++ b/arch/arm/mach-prima2/hotplug.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * CPU hotplug support for CSR Marco dual-core SMP SoCs | ||
3 | * | ||
4 | * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
5 | * | ||
6 | * Licensed under GPLv2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/smp.h> | ||
12 | |||
13 | #include <asm/cacheflush.h> | ||
14 | #include <asm/smp_plat.h> | ||
15 | |||
16 | static inline void platform_do_lowpower(unsigned int cpu) | ||
17 | { | ||
18 | flush_cache_all(); | ||
19 | |||
20 | /* we put the platform to just WFI */ | ||
21 | for (;;) { | ||
22 | __asm__ __volatile__("dsb\n\t" "wfi\n\t" | ||
23 | : : : "memory"); | ||
24 | if (pen_release == cpu_logical_map(cpu)) { | ||
25 | /* | ||
26 | * OK, proper wakeup, we're done | ||
27 | */ | ||
28 | break; | ||
29 | } | ||
30 | } | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * platform-specific code to shutdown a CPU | ||
35 | * | ||
36 | * Called with IRQs disabled | ||
37 | */ | ||
38 | void sirfsoc_cpu_die(unsigned int cpu) | ||
39 | { | ||
40 | platform_do_lowpower(cpu); | ||
41 | } | ||
diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h index f6014a07541f..b778a0f248ed 100644 --- a/arch/arm/mach-prima2/include/mach/irqs.h +++ b/arch/arm/mach-prima2/include/mach/irqs.h | |||
@@ -10,8 +10,8 @@ | |||
10 | #define __ASM_ARCH_IRQS_H | 10 | #define __ASM_ARCH_IRQS_H |
11 | 11 | ||
12 | #define SIRFSOC_INTENAL_IRQ_START 0 | 12 | #define SIRFSOC_INTENAL_IRQ_START 0 |
13 | #define SIRFSOC_INTENAL_IRQ_END 59 | 13 | #define SIRFSOC_INTENAL_IRQ_END 127 |
14 | #define SIRFSOC_GPIO_IRQ_START (SIRFSOC_INTENAL_IRQ_END + 1) | 14 | #define SIRFSOC_GPIO_IRQ_START (SIRFSOC_INTENAL_IRQ_END + 1) |
15 | #define NR_IRQS 220 | 15 | #define NR_IRQS 288 |
16 | 16 | ||
17 | #endif | 17 | #endif |
diff --git a/arch/arm/mach-prima2/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h index c98b4d5ac24a..c10510d01a44 100644 --- a/arch/arm/mach-prima2/include/mach/uart.h +++ b/arch/arm/mach-prima2/include/mach/uart.h | |||
@@ -10,7 +10,13 @@ | |||
10 | #define __MACH_PRIMA2_SIRFSOC_UART_H | 10 | #define __MACH_PRIMA2_SIRFSOC_UART_H |
11 | 11 | ||
12 | /* UART-1: used as serial debug port */ | 12 | /* UART-1: used as serial debug port */ |
13 | #if defined(CONFIG_DEBUG_SIRFPRIMA2_UART1) | ||
13 | #define SIRFSOC_UART1_PA_BASE 0xb0060000 | 14 | #define SIRFSOC_UART1_PA_BASE 0xb0060000 |
15 | #elif defined(CONFIG_DEBUG_SIRFMARCO_UART1) | ||
16 | #define SIRFSOC_UART1_PA_BASE 0xcc060000 | ||
17 | #else | ||
18 | #define SIRFSOC_UART1_PA_BASE 0 | ||
19 | #endif | ||
14 | #define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000) | 20 | #define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000) |
15 | #define SIRFSOC_UART1_SIZE SZ_4K | 21 | #define SIRFSOC_UART1_SIZE SZ_4K |
16 | 22 | ||
diff --git a/arch/arm/mach-prima2/include/mach/uncompress.h b/arch/arm/mach-prima2/include/mach/uncompress.h index 0c898fcf909c..15f3edcfbb47 100644 --- a/arch/arm/mach-prima2/include/mach/uncompress.h +++ b/arch/arm/mach-prima2/include/mach/uncompress.h | |||
@@ -25,6 +25,9 @@ static __inline__ void putc(char c) | |||
25 | * during kernel decompression, all mappings are flat: | 25 | * during kernel decompression, all mappings are flat: |
26 | * virt_addr == phys_addr | 26 | * virt_addr == phys_addr |
27 | */ | 27 | */ |
28 | if (!SIRFSOC_UART1_PA_BASE) | ||
29 | return; | ||
30 | |||
28 | while (__raw_readl((void __iomem *)SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS) | 31 | while (__raw_readl((void __iomem *)SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS) |
29 | & SIRFSOC_UART1_TXFIFO_FULL) | 32 | & SIRFSOC_UART1_TXFIFO_FULL) |
30 | barrier(); | 33 | barrier(); |
diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c index 7dee9176e77a..6c0f3e9c43fb 100644 --- a/arch/arm/mach-prima2/irq.c +++ b/arch/arm/mach-prima2/irq.c | |||
@@ -9,17 +9,19 @@ | |||
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/io.h> | 10 | #include <linux/io.h> |
11 | #include <linux/irq.h> | 11 | #include <linux/irq.h> |
12 | #include <mach/hardware.h> | ||
13 | #include <asm/mach/irq.h> | ||
14 | #include <linux/of.h> | 12 | #include <linux/of.h> |
15 | #include <linux/of_address.h> | 13 | #include <linux/of_address.h> |
16 | #include <linux/irqdomain.h> | 14 | #include <linux/irqdomain.h> |
17 | #include <linux/syscore_ops.h> | 15 | #include <linux/syscore_ops.h> |
16 | #include <asm/mach/irq.h> | ||
17 | #include <asm/exception.h> | ||
18 | #include <mach/hardware.h> | ||
18 | 19 | ||
19 | #define SIRFSOC_INT_RISC_MASK0 0x0018 | 20 | #define SIRFSOC_INT_RISC_MASK0 0x0018 |
20 | #define SIRFSOC_INT_RISC_MASK1 0x001C | 21 | #define SIRFSOC_INT_RISC_MASK1 0x001C |
21 | #define SIRFSOC_INT_RISC_LEVEL0 0x0020 | 22 | #define SIRFSOC_INT_RISC_LEVEL0 0x0020 |
22 | #define SIRFSOC_INT_RISC_LEVEL1 0x0024 | 23 | #define SIRFSOC_INT_RISC_LEVEL1 0x0024 |
24 | #define SIRFSOC_INIT_IRQ_ID 0x0038 | ||
23 | 25 | ||
24 | void __iomem *sirfsoc_intc_base; | 26 | void __iomem *sirfsoc_intc_base; |
25 | 27 | ||
@@ -52,6 +54,16 @@ static __init void sirfsoc_irq_init(void) | |||
52 | writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1); | 54 | writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1); |
53 | } | 55 | } |
54 | 56 | ||
57 | asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs) | ||
58 | { | ||
59 | u32 irqstat, irqnr; | ||
60 | |||
61 | irqstat = readl_relaxed(sirfsoc_intc_base + SIRFSOC_INIT_IRQ_ID); | ||
62 | irqnr = irqstat & 0xff; | ||
63 | |||
64 | handle_IRQ(irqnr, regs); | ||
65 | } | ||
66 | |||
55 | static struct of_device_id intc_ids[] = { | 67 | static struct of_device_id intc_ids[] = { |
56 | { .compatible = "sirf,prima2-intc" }, | 68 | { .compatible = "sirf,prima2-intc" }, |
57 | {}, | 69 | {}, |
diff --git a/arch/arm/mach-prima2/l2x0.c b/arch/arm/mach-prima2/l2x0.c index c99837797d76..cbcbe9cb094c 100644 --- a/arch/arm/mach-prima2/l2x0.c +++ b/arch/arm/mach-prima2/l2x0.c | |||
@@ -11,19 +11,38 @@ | |||
11 | #include <linux/of.h> | 11 | #include <linux/of.h> |
12 | #include <asm/hardware/cache-l2x0.h> | 12 | #include <asm/hardware/cache-l2x0.h> |
13 | 13 | ||
14 | static struct of_device_id prima2_l2x0_ids[] = { | 14 | struct l2x0_aux |
15 | { .compatible = "sirf,prima2-pl310-cache" }, | 15 | { |
16 | u32 val; | ||
17 | u32 mask; | ||
18 | }; | ||
19 | |||
20 | static struct l2x0_aux prima2_l2x0_aux __initconst = { | ||
21 | .val = 2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT, | ||
22 | .mask = 0, | ||
23 | }; | ||
24 | |||
25 | static struct l2x0_aux marco_l2x0_aux __initconst = { | ||
26 | .val = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | | ||
27 | (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT), | ||
28 | .mask = L2X0_AUX_CTRL_MASK, | ||
29 | }; | ||
30 | |||
31 | static struct of_device_id sirf_l2x0_ids[] __initconst = { | ||
32 | { .compatible = "sirf,prima2-pl310-cache", .data = &prima2_l2x0_aux, }, | ||
33 | { .compatible = "sirf,marco-pl310-cache", .data = &marco_l2x0_aux, }, | ||
16 | {}, | 34 | {}, |
17 | }; | 35 | }; |
18 | 36 | ||
19 | static int __init sirfsoc_l2x0_init(void) | 37 | static int __init sirfsoc_l2x0_init(void) |
20 | { | 38 | { |
21 | struct device_node *np; | 39 | struct device_node *np; |
40 | const struct l2x0_aux *aux; | ||
22 | 41 | ||
23 | np = of_find_matching_node(NULL, prima2_l2x0_ids); | 42 | np = of_find_matching_node(NULL, sirf_l2x0_ids); |
24 | if (np) { | 43 | if (np) { |
25 | pr_info("Initializing prima2 L2 cache\n"); | 44 | aux = of_match_node(sirf_l2x0_ids, np)->data; |
26 | return l2x0_of_init(0x40000, 0); | 45 | return l2x0_of_init(aux->val, aux->mask); |
27 | } | 46 | } |
28 | 47 | ||
29 | return 0; | 48 | return 0; |
diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c new file mode 100644 index 000000000000..2395022bc733 --- /dev/null +++ b/arch/arm/mach-prima2/platsmp.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * plat smp support for CSR Marco dual-core SMP SoCs | ||
3 | * | ||
4 | * Copyright (c) 2012 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
5 | * | ||
6 | * Licensed under GPLv2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/smp.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/of.h> | ||
13 | #include <linux/of_address.h> | ||
14 | #include <asm/page.h> | ||
15 | #include <asm/mach/map.h> | ||
16 | #include <asm/smp_plat.h> | ||
17 | #include <asm/smp_scu.h> | ||
18 | #include <asm/cacheflush.h> | ||
19 | #include <asm/cputype.h> | ||
20 | #include <asm/hardware/gic.h> | ||
21 | #include <mach/map.h> | ||
22 | |||
23 | #include "common.h" | ||
24 | |||
25 | static void __iomem *scu_base; | ||
26 | static void __iomem *rsc_base; | ||
27 | |||
28 | static DEFINE_SPINLOCK(boot_lock); | ||
29 | |||
30 | static struct map_desc scu_io_desc __initdata = { | ||
31 | .length = SZ_4K, | ||
32 | .type = MT_DEVICE, | ||
33 | }; | ||
34 | |||
35 | void __init sirfsoc_map_scu(void) | ||
36 | { | ||
37 | unsigned long base; | ||
38 | |||
39 | /* Get SCU base */ | ||
40 | asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); | ||
41 | |||
42 | scu_io_desc.virtual = SIRFSOC_VA(base); | ||
43 | scu_io_desc.pfn = __phys_to_pfn(base); | ||
44 | iotable_init(&scu_io_desc, 1); | ||
45 | |||
46 | scu_base = (void __iomem *)SIRFSOC_VA(base); | ||
47 | } | ||
48 | |||
49 | static void __cpuinit sirfsoc_secondary_init(unsigned int cpu) | ||
50 | { | ||
51 | /* | ||
52 | * if any interrupts are already enabled for the primary | ||
53 | * core (e.g. timer irq), then they will not have been enabled | ||
54 | * for us: do so | ||
55 | */ | ||
56 | gic_secondary_init(0); | ||
57 | |||
58 | /* | ||
59 | * let the primary processor know we're out of the | ||
60 | * pen, then head off into the C entry point | ||
61 | */ | ||
62 | pen_release = -1; | ||
63 | smp_wmb(); | ||
64 | |||
65 | /* | ||
66 | * Synchronise with the boot thread. | ||
67 | */ | ||
68 | spin_lock(&boot_lock); | ||
69 | spin_unlock(&boot_lock); | ||
70 | } | ||
71 | |||
72 | static struct of_device_id rsc_ids[] = { | ||
73 | { .compatible = "sirf,marco-rsc" }, | ||
74 | {}, | ||
75 | }; | ||
76 | |||
77 | static int __cpuinit sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
78 | { | ||
79 | unsigned long timeout; | ||
80 | struct device_node *np; | ||
81 | |||
82 | np = of_find_matching_node(NULL, rsc_ids); | ||
83 | if (!np) | ||
84 | return -ENODEV; | ||
85 | |||
86 | rsc_base = of_iomap(np, 0); | ||
87 | if (!rsc_base) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | /* | ||
91 | * write the address of secondary startup into the sram register | ||
92 | * at offset 0x2C, then write the magic number 0x3CAF5D62 to the | ||
93 | * RSC register at offset 0x28, which is what boot rom code is | ||
94 | * waiting for. This would wake up the secondary core from WFE | ||
95 | */ | ||
96 | #define SIRFSOC_CPU1_JUMPADDR_OFFSET 0x2C | ||
97 | __raw_writel(virt_to_phys(sirfsoc_secondary_startup), | ||
98 | rsc_base + SIRFSOC_CPU1_JUMPADDR_OFFSET); | ||
99 | |||
100 | #define SIRFSOC_CPU1_WAKEMAGIC_OFFSET 0x28 | ||
101 | __raw_writel(0x3CAF5D62, | ||
102 | rsc_base + SIRFSOC_CPU1_WAKEMAGIC_OFFSET); | ||
103 | |||
104 | /* make sure write buffer is drained */ | ||
105 | mb(); | ||
106 | |||
107 | spin_lock(&boot_lock); | ||
108 | |||
109 | /* | ||
110 | * The secondary processor is waiting to be released from | ||
111 | * the holding pen - release it, then wait for it to flag | ||
112 | * that it has been released by resetting pen_release. | ||
113 | * | ||
114 | * Note that "pen_release" is the hardware CPU ID, whereas | ||
115 | * "cpu" is Linux's internal ID. | ||
116 | */ | ||
117 | pen_release = cpu_logical_map(cpu); | ||
118 | __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); | ||
119 | outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); | ||
120 | |||
121 | /* | ||
122 | * Send the secondary CPU SEV, thereby causing the boot monitor to read | ||
123 | * the JUMPADDR and WAKEMAGIC, and branch to the address found there. | ||
124 | */ | ||
125 | dsb_sev(); | ||
126 | |||
127 | timeout = jiffies + (1 * HZ); | ||
128 | while (time_before(jiffies, timeout)) { | ||
129 | smp_rmb(); | ||
130 | if (pen_release == -1) | ||
131 | break; | ||
132 | |||
133 | udelay(10); | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * now the secondary core is starting up let it run its | ||
138 | * calibrations, then wait for it to finish | ||
139 | */ | ||
140 | spin_unlock(&boot_lock); | ||
141 | |||
142 | return pen_release != -1 ? -ENOSYS : 0; | ||
143 | } | ||
144 | |||
145 | static void __init sirfsoc_smp_init_cpus(void) | ||
146 | { | ||
147 | set_smp_cross_call(gic_raise_softirq); | ||
148 | } | ||
149 | |||
150 | static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus) | ||
151 | { | ||
152 | scu_enable(scu_base); | ||
153 | } | ||
154 | |||
155 | struct smp_operations sirfsoc_smp_ops __initdata = { | ||
156 | .smp_init_cpus = sirfsoc_smp_init_cpus, | ||
157 | .smp_prepare_cpus = sirfsoc_smp_prepare_cpus, | ||
158 | .smp_secondary_init = sirfsoc_secondary_init, | ||
159 | .smp_boot_secondary = sirfsoc_boot_secondary, | ||
160 | #ifdef CONFIG_HOTPLUG_CPU | ||
161 | .cpu_die = sirfsoc_cpu_die, | ||
162 | #endif | ||
163 | }; | ||
diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c index 762adb73ab7c..435019ca0a48 100644 --- a/arch/arm/mach-prima2/rstc.c +++ b/arch/arm/mach-prima2/rstc.c | |||
@@ -19,6 +19,7 @@ static DEFINE_MUTEX(rstc_lock); | |||
19 | 19 | ||
20 | static struct of_device_id rstc_ids[] = { | 20 | static struct of_device_id rstc_ids[] = { |
21 | { .compatible = "sirf,prima2-rstc" }, | 21 | { .compatible = "sirf,prima2-rstc" }, |
22 | { .compatible = "sirf,marco-rstc" }, | ||
22 | {}, | 23 | {}, |
23 | }; | 24 | }; |
24 | 25 | ||
@@ -42,27 +43,37 @@ early_initcall(sirfsoc_of_rstc_init); | |||
42 | 43 | ||
43 | int sirfsoc_reset_device(struct device *dev) | 44 | int sirfsoc_reset_device(struct device *dev) |
44 | { | 45 | { |
45 | const unsigned int *prop = of_get_property(dev->of_node, "reset-bit", NULL); | 46 | u32 reset_bit; |
46 | unsigned int reset_bit; | ||
47 | 47 | ||
48 | if (!prop) | 48 | if (of_property_read_u32(dev->of_node, "reset-bit", &reset_bit)) |
49 | return -ENODEV; | 49 | return -EINVAL; |
50 | |||
51 | reset_bit = be32_to_cpup(prop); | ||
52 | 50 | ||
53 | mutex_lock(&rstc_lock); | 51 | mutex_lock(&rstc_lock); |
54 | 52 | ||
55 | /* | 53 | if (of_device_is_compatible(dev->of_node, "sirf,prima2-rstc")) { |
56 | * Writing 1 to this bit resets corresponding block. Writing 0 to this | 54 | /* |
57 | * bit de-asserts reset signal of the corresponding block. | 55 | * Writing 1 to this bit resets corresponding block. Writing 0 to this |
58 | * datasheet doesn't require explicit delay between the set and clear | 56 | * bit de-asserts reset signal of the corresponding block. |
59 | * of reset bit. it could be shorter if tests pass. | 57 | * datasheet doesn't require explicit delay between the set and clear |
60 | */ | 58 | * of reset bit. it could be shorter if tests pass. |
61 | writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit, | 59 | */ |
62 | sirfsoc_rstc_base + (reset_bit / 32) * 4); | 60 | writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit, |
63 | msleep(10); | 61 | sirfsoc_rstc_base + (reset_bit / 32) * 4); |
64 | writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit, | 62 | msleep(10); |
65 | sirfsoc_rstc_base + (reset_bit / 32) * 4); | 63 | writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit, |
64 | sirfsoc_rstc_base + (reset_bit / 32) * 4); | ||
65 | } else { | ||
66 | /* | ||
67 | * For MARCO and POLO | ||
68 | * Writing 1 to SET register resets corresponding block. Writing 1 to CLEAR | ||
69 | * register de-asserts reset signal of the corresponding block. | ||
70 | * datasheet doesn't require explicit delay between the set and clear | ||
71 | * of reset bit. it could be shorter if tests pass. | ||
72 | */ | ||
73 | writel(reset_bit, sirfsoc_rstc_base + (reset_bit / 32) * 8); | ||
74 | msleep(10); | ||
75 | writel(reset_bit, sirfsoc_rstc_base + (reset_bit / 32) * 8 + 4); | ||
76 | } | ||
66 | 77 | ||
67 | mutex_unlock(&rstc_lock); | 78 | mutex_unlock(&rstc_lock); |
68 | 79 | ||
diff --git a/arch/arm/mach-prima2/rtciobrg.c b/arch/arm/mach-prima2/rtciobrg.c index 557353602130..9f2da2eec4dc 100644 --- a/arch/arm/mach-prima2/rtciobrg.c +++ b/arch/arm/mach-prima2/rtciobrg.c | |||
@@ -104,6 +104,7 @@ EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_writel); | |||
104 | 104 | ||
105 | static const struct of_device_id rtciobrg_ids[] = { | 105 | static const struct of_device_id rtciobrg_ids[] = { |
106 | { .compatible = "sirf,prima2-rtciobg" }, | 106 | { .compatible = "sirf,prima2-rtciobg" }, |
107 | { .compatible = "sirf,marco-rtciobg" }, | ||
107 | {} | 108 | {} |
108 | }; | 109 | }; |
109 | 110 | ||
diff --git a/arch/arm/mach-prima2/timer-marco.c b/arch/arm/mach-prima2/timer-marco.c new file mode 100644 index 000000000000..f4eea2e97eb0 --- /dev/null +++ b/arch/arm/mach-prima2/timer-marco.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * System timer for CSR SiRFprimaII | ||
3 | * | ||
4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
5 | * | ||
6 | * Licensed under GPLv2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/clockchips.h> | ||
12 | #include <linux/clocksource.h> | ||
13 | #include <linux/bitops.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_irq.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <asm/sched_clock.h> | ||
21 | #include <asm/localtimer.h> | ||
22 | #include <asm/mach/time.h> | ||
23 | |||
24 | #include "common.h" | ||
25 | |||
26 | #define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 | ||
27 | #define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004 | ||
28 | #define SIRFSOC_TIMER_MATCH_0 0x0018 | ||
29 | #define SIRFSOC_TIMER_MATCH_1 0x001c | ||
30 | #define SIRFSOC_TIMER_COUNTER_0 0x0048 | ||
31 | #define SIRFSOC_TIMER_COUNTER_1 0x004c | ||
32 | #define SIRFSOC_TIMER_INTR_STATUS 0x0060 | ||
33 | #define SIRFSOC_TIMER_WATCHDOG_EN 0x0064 | ||
34 | #define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068 | ||
35 | #define SIRFSOC_TIMER_64COUNTER_LO 0x006c | ||
36 | #define SIRFSOC_TIMER_64COUNTER_HI 0x0070 | ||
37 | #define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074 | ||
38 | #define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078 | ||
39 | #define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c | ||
40 | #define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080 | ||
41 | |||
42 | #define SIRFSOC_TIMER_REG_CNT 6 | ||
43 | |||
44 | static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = { | ||
45 | SIRFSOC_TIMER_WATCHDOG_EN, | ||
46 | SIRFSOC_TIMER_32COUNTER_0_CTRL, | ||
47 | SIRFSOC_TIMER_32COUNTER_1_CTRL, | ||
48 | SIRFSOC_TIMER_64COUNTER_CTRL, | ||
49 | SIRFSOC_TIMER_64COUNTER_RLATCHED_LO, | ||
50 | SIRFSOC_TIMER_64COUNTER_RLATCHED_HI, | ||
51 | }; | ||
52 | |||
53 | static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT]; | ||
54 | |||
55 | static void __iomem *sirfsoc_timer_base; | ||
56 | static void __init sirfsoc_of_timer_map(void); | ||
57 | |||
58 | /* disable count and interrupt */ | ||
59 | static inline void sirfsoc_timer_count_disable(int idx) | ||
60 | { | ||
61 | writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7, | ||
62 | sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); | ||
63 | } | ||
64 | |||
65 | /* enable count and interrupt */ | ||
66 | static inline void sirfsoc_timer_count_enable(int idx) | ||
67 | { | ||
68 | writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x7, | ||
69 | sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx); | ||
70 | } | ||
71 | |||
72 | /* timer interrupt handler */ | ||
73 | static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) | ||
74 | { | ||
75 | struct clock_event_device *ce = dev_id; | ||
76 | int cpu = smp_processor_id(); | ||
77 | |||
78 | /* clear timer interrupt */ | ||
79 | writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); | ||
80 | |||
81 | if (ce->mode == CLOCK_EVT_MODE_ONESHOT) | ||
82 | sirfsoc_timer_count_disable(cpu); | ||
83 | |||
84 | ce->event_handler(ce); | ||
85 | |||
86 | return IRQ_HANDLED; | ||
87 | } | ||
88 | |||
89 | /* read 64-bit timer counter */ | ||
90 | static cycle_t sirfsoc_timer_read(struct clocksource *cs) | ||
91 | { | ||
92 | u64 cycles; | ||
93 | |||
94 | writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | | ||
95 | BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); | ||
96 | |||
97 | cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI); | ||
98 | cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO); | ||
99 | |||
100 | return cycles; | ||
101 | } | ||
102 | |||
103 | static int sirfsoc_timer_set_next_event(unsigned long delta, | ||
104 | struct clock_event_device *ce) | ||
105 | { | ||
106 | int cpu = smp_processor_id(); | ||
107 | |||
108 | writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 + | ||
109 | 4 * cpu); | ||
110 | writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 + | ||
111 | 4 * cpu); | ||
112 | |||
113 | /* enable the tick */ | ||
114 | sirfsoc_timer_count_enable(cpu); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static void sirfsoc_timer_set_mode(enum clock_event_mode mode, | ||
120 | struct clock_event_device *ce) | ||
121 | { | ||
122 | switch (mode) { | ||
123 | case CLOCK_EVT_MODE_ONESHOT: | ||
124 | /* enable in set_next_event */ | ||
125 | break; | ||
126 | default: | ||
127 | break; | ||
128 | } | ||
129 | |||
130 | sirfsoc_timer_count_disable(smp_processor_id()); | ||
131 | } | ||
132 | |||
133 | static void sirfsoc_clocksource_suspend(struct clocksource *cs) | ||
134 | { | ||
135 | int i; | ||
136 | |||
137 | for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++) | ||
138 | sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); | ||
139 | } | ||
140 | |||
141 | static void sirfsoc_clocksource_resume(struct clocksource *cs) | ||
142 | { | ||
143 | int i; | ||
144 | |||
145 | for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++) | ||
146 | writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); | ||
147 | |||
148 | writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2], | ||
149 | sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); | ||
150 | writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1], | ||
151 | sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); | ||
152 | |||
153 | writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | | ||
154 | BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); | ||
155 | } | ||
156 | |||
157 | static struct clock_event_device sirfsoc_clockevent = { | ||
158 | .name = "sirfsoc_clockevent", | ||
159 | .rating = 200, | ||
160 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
161 | .set_mode = sirfsoc_timer_set_mode, | ||
162 | .set_next_event = sirfsoc_timer_set_next_event, | ||
163 | }; | ||
164 | |||
165 | static struct clocksource sirfsoc_clocksource = { | ||
166 | .name = "sirfsoc_clocksource", | ||
167 | .rating = 200, | ||
168 | .mask = CLOCKSOURCE_MASK(64), | ||
169 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
170 | .read = sirfsoc_timer_read, | ||
171 | .suspend = sirfsoc_clocksource_suspend, | ||
172 | .resume = sirfsoc_clocksource_resume, | ||
173 | }; | ||
174 | |||
175 | static struct irqaction sirfsoc_timer_irq = { | ||
176 | .name = "sirfsoc_timer0", | ||
177 | .flags = IRQF_TIMER | IRQF_NOBALANCING, | ||
178 | .handler = sirfsoc_timer_interrupt, | ||
179 | .dev_id = &sirfsoc_clockevent, | ||
180 | }; | ||
181 | |||
182 | #ifdef CONFIG_LOCAL_TIMERS | ||
183 | |||
184 | static struct irqaction sirfsoc_timer1_irq = { | ||
185 | .name = "sirfsoc_timer1", | ||
186 | .flags = IRQF_TIMER | IRQF_NOBALANCING, | ||
187 | .handler = sirfsoc_timer_interrupt, | ||
188 | }; | ||
189 | |||
190 | static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce) | ||
191 | { | ||
192 | /* Use existing clock_event for cpu 0 */ | ||
193 | if (!smp_processor_id()) | ||
194 | return 0; | ||
195 | |||
196 | ce->irq = sirfsoc_timer1_irq.irq; | ||
197 | ce->name = "local_timer"; | ||
198 | ce->features = sirfsoc_clockevent.features; | ||
199 | ce->rating = sirfsoc_clockevent.rating; | ||
200 | ce->set_mode = sirfsoc_timer_set_mode; | ||
201 | ce->set_next_event = sirfsoc_timer_set_next_event; | ||
202 | ce->shift = sirfsoc_clockevent.shift; | ||
203 | ce->mult = sirfsoc_clockevent.mult; | ||
204 | ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns; | ||
205 | ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns; | ||
206 | |||
207 | sirfsoc_timer1_irq.dev_id = ce; | ||
208 | BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq)); | ||
209 | irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1)); | ||
210 | |||
211 | clockevents_register_device(ce); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static void sirfsoc_local_timer_stop(struct clock_event_device *ce) | ||
216 | { | ||
217 | sirfsoc_timer_count_disable(1); | ||
218 | |||
219 | remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); | ||
220 | } | ||
221 | |||
222 | static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = { | ||
223 | .setup = sirfsoc_local_timer_setup, | ||
224 | .stop = sirfsoc_local_timer_stop, | ||
225 | }; | ||
226 | #endif /* CONFIG_LOCAL_TIMERS */ | ||
227 | |||
228 | static void __init sirfsoc_clockevent_init(void) | ||
229 | { | ||
230 | clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); | ||
231 | |||
232 | sirfsoc_clockevent.max_delta_ns = | ||
233 | clockevent_delta2ns(-2, &sirfsoc_clockevent); | ||
234 | sirfsoc_clockevent.min_delta_ns = | ||
235 | clockevent_delta2ns(2, &sirfsoc_clockevent); | ||
236 | |||
237 | sirfsoc_clockevent.cpumask = cpumask_of(0); | ||
238 | clockevents_register_device(&sirfsoc_clockevent); | ||
239 | #ifdef CONFIG_LOCAL_TIMERS | ||
240 | local_timer_register(&sirfsoc_local_timer_ops); | ||
241 | #endif | ||
242 | } | ||
243 | |||
244 | /* initialize the kernel jiffy timer source */ | ||
245 | void __init sirfsoc_marco_timer_init(void) | ||
246 | { | ||
247 | unsigned long rate; | ||
248 | u32 timer_div; | ||
249 | struct clk *clk; | ||
250 | |||
251 | /* initialize clocking early, we want to set the OS timer */ | ||
252 | sirfsoc_of_clk_init(); | ||
253 | |||
254 | /* timer's input clock is io clock */ | ||
255 | clk = clk_get_sys("io", NULL); | ||
256 | |||
257 | BUG_ON(IS_ERR(clk)); | ||
258 | rate = clk_get_rate(clk); | ||
259 | |||
260 | BUG_ON(rate < CLOCK_TICK_RATE); | ||
261 | BUG_ON(rate % CLOCK_TICK_RATE); | ||
262 | |||
263 | sirfsoc_of_timer_map(); | ||
264 | |||
265 | /* Initialize the timer dividers */ | ||
266 | timer_div = rate / CLOCK_TICK_RATE - 1; | ||
267 | writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); | ||
268 | writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL); | ||
269 | writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL); | ||
270 | |||
271 | /* Initialize timer counters to 0 */ | ||
272 | writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO); | ||
273 | writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI); | ||
274 | writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) | | ||
275 | BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); | ||
276 | writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0); | ||
277 | writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1); | ||
278 | |||
279 | /* Clear all interrupts */ | ||
280 | writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); | ||
281 | |||
282 | BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); | ||
283 | |||
284 | BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); | ||
285 | |||
286 | sirfsoc_clockevent_init(); | ||
287 | } | ||
288 | |||
289 | static struct of_device_id timer_ids[] = { | ||
290 | { .compatible = "sirf,marco-tick" }, | ||
291 | {}, | ||
292 | }; | ||
293 | |||
294 | static void __init sirfsoc_of_timer_map(void) | ||
295 | { | ||
296 | struct device_node *np; | ||
297 | |||
298 | np = of_find_matching_node(NULL, timer_ids); | ||
299 | if (!np) | ||
300 | return; | ||
301 | sirfsoc_timer_base = of_iomap(np, 0); | ||
302 | if (!sirfsoc_timer_base) | ||
303 | panic("unable to map timer cpu registers\n"); | ||
304 | |||
305 | sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); | ||
306 | if (!sirfsoc_timer_irq.irq) | ||
307 | panic("No irq passed for timer0 via DT\n"); | ||
308 | |||
309 | #ifdef CONFIG_LOCAL_TIMERS | ||
310 | sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); | ||
311 | if (!sirfsoc_timer1_irq.irq) | ||
312 | panic("No irq passed for timer1 via DT\n"); | ||
313 | #endif | ||
314 | |||
315 | of_node_put(np); | ||
316 | } | ||
diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer-prima2.c index a7a2c199c3ea..6da584f8a949 100644 --- a/arch/arm/mach-prima2/timer.c +++ b/arch/arm/mach-prima2/timer-prima2.c | |||
@@ -181,7 +181,7 @@ static void __init sirfsoc_clockevent_init(void) | |||
181 | } | 181 | } |
182 | 182 | ||
183 | /* initialize the kernel jiffy timer source */ | 183 | /* initialize the kernel jiffy timer source */ |
184 | void __init sirfsoc_timer_init(void) | 184 | void __init sirfsoc_prima2_timer_init(void) |
185 | { | 185 | { |
186 | unsigned long rate; | 186 | unsigned long rate; |
187 | struct clk *clk; | 187 | struct clk *clk; |
@@ -220,14 +220,14 @@ static struct of_device_id timer_ids[] = { | |||
220 | {}, | 220 | {}, |
221 | }; | 221 | }; |
222 | 222 | ||
223 | void __init sirfsoc_of_timer_map(void) | 223 | static void __init sirfsoc_of_timer_map(void) |
224 | { | 224 | { |
225 | struct device_node *np; | 225 | struct device_node *np; |
226 | const unsigned int *intspec; | 226 | const unsigned int *intspec; |
227 | 227 | ||
228 | np = of_find_matching_node(NULL, timer_ids); | 228 | np = of_find_matching_node(NULL, timer_ids); |
229 | if (!np) | 229 | if (!np) |
230 | panic("unable to find compatible timer node in dtb\n"); | 230 | return; |
231 | sirfsoc_timer_base = of_iomap(np, 0); | 231 | sirfsoc_timer_base = of_iomap(np, 0); |
232 | if (!sirfsoc_timer_base) | 232 | if (!sirfsoc_timer_base) |
233 | panic("unable to map timer cpu registers\n"); | 233 | panic("unable to map timer cpu registers\n"); |