aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-22 22:21:08 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-22 22:21:08 -0400
commitf10f114f199dbcb9e1d6b5a0b36a34acf93f6179 (patch)
tree299058a338e245957bf9e132f5cbf222bd03cad6 /arch/mips
parent0c326331c8b107abc0a160e8899d749150b8f76a (diff)
parentdab969c00b8bee17a47057bbb91cd0a348cf6f76 (diff)
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: [MIPS] time: Make c0_compare_int_usable more bullet proof [MIPS] Kbuild: Use the new cc-cross-prefix feature. [MIPS] Fix include wrapper symbol to something sane. [MIPS] Malta: Delete dead code. [MIPS] time: Add GT641xx timer0 clockevent driver [MIPS] time: SMP-proofing of Sibyte clockevent/clocksource code. [MIPS] time: SMP/NUMA-proofing of IP27 HUB RT timer code. [MIPS] time: Fix calculation in clockevent_set_clock()
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig4
-rw-r--r--arch/mips/Kconfig.debug12
-rw-r--r--arch/mips/Makefile18
-rw-r--r--arch/mips/cobalt/Makefile2
-rw-r--r--arch/mips/cobalt/setup.c24
-rw-r--r--arch/mips/cobalt/time.c35
-rw-r--r--arch/mips/kernel/Makefile1
-rw-r--r--arch/mips/kernel/cevt-gt641xx.c144
-rw-r--r--arch/mips/kernel/cevt-r4k.c4
-rw-r--r--arch/mips/kernel/time.c4
-rw-r--r--arch/mips/mips-boards/generic/time.c13
-rw-r--r--arch/mips/sgi-ip27/ip27-init.c2
-rw-r--r--arch/mips/sgi-ip27/ip27-timer.c134
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c75
-rw-r--r--arch/mips/sibyte/bcm1480/smp.c4
-rw-r--r--arch/mips/sibyte/bcm1480/time.c117
-rw-r--r--arch/mips/sibyte/sb1250/irq.c35
-rw-r--r--arch/mips/sibyte/sb1250/smp.c4
-rw-r--r--arch/mips/sibyte/sb1250/time.c88
19 files changed, 432 insertions, 288 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3ecff5e9e4f3..61262c5f9c62 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -66,6 +66,7 @@ config BCM47XX
66config MIPS_COBALT 66config MIPS_COBALT
67 bool "Cobalt Server" 67 bool "Cobalt Server"
68 select CEVT_R4K 68 select CEVT_R4K
69 select CEVT_GT641XX
69 select DMA_NONCOHERENT 70 select DMA_NONCOHERENT
70 select HW_HAS_PCI 71 select HW_HAS_PCI
71 select I8253 72 select I8253
@@ -729,6 +730,9 @@ config ARCH_MAY_HAVE_PC_FDC
729config BOOT_RAW 730config BOOT_RAW
730 bool 731 bool
731 732
733config CEVT_GT641XX
734 bool
735
732config CEVT_R4K 736config CEVT_R4K
733 bool 737 bool
734 738
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 3efe117721aa..fd7124c1b75a 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -6,18 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
6 6
7source "lib/Kconfig.debug" 7source "lib/Kconfig.debug"
8 8
9config CROSSCOMPILE
10 bool "Are you using a crosscompiler"
11 help
12 Say Y here if you are compiling the kernel on a different
13 architecture than the one it is intended to run on. This is just a
14 convenience option which will select the appropriate value for
15 the CROSS_COMPILE make variable which otherwise has to be passed on
16 the command line from mips-linux-, mipsel-linux-, mips64-linux- and
17 mips64el-linux- as appropriate for a particular kernel configuration.
18 You will have to pass the value for CROSS_COMPILE manually if the
19 name prefix for your tools is different.
20
21config CMDLINE 9config CMDLINE
22 string "Default kernel command string" 10 string "Default kernel command string"
23 default "" 11 default ""
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 14164c2b8791..23c17755eca0 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -18,15 +18,15 @@ cflags-y :=
18# Select the object file format to substitute into the linker script. 18# Select the object file format to substitute into the linker script.
19# 19#
20ifdef CONFIG_CPU_LITTLE_ENDIAN 20ifdef CONFIG_CPU_LITTLE_ENDIAN
2132bit-tool-prefix = mipsel-linux- 2132bit-tool-archpref = mipsel
2264bit-tool-prefix = mips64el-linux- 2264bit-tool-archpref = mips64el
2332bit-bfd = elf32-tradlittlemips 2332bit-bfd = elf32-tradlittlemips
2464bit-bfd = elf64-tradlittlemips 2464bit-bfd = elf64-tradlittlemips
2532bit-emul = elf32ltsmip 2532bit-emul = elf32ltsmip
2664bit-emul = elf64ltsmip 2664bit-emul = elf64ltsmip
27else 27else
2832bit-tool-prefix = mips-linux- 2832bit-tool-archpref = mips
2964bit-tool-prefix = mips64-linux- 2964bit-tool-archpref = mips64
3032bit-bfd = elf32-tradbigmips 3032bit-bfd = elf32-tradbigmips
3164bit-bfd = elf64-tradbigmips 3164bit-bfd = elf64-tradbigmips
3232bit-emul = elf32btsmip 3232bit-emul = elf32btsmip
@@ -34,16 +34,18 @@ else
34endif 34endif
35 35
36ifdef CONFIG_32BIT 36ifdef CONFIG_32BIT
37tool-prefix = $(32bit-tool-prefix) 37tool-archpref = $(32bit-tool-archpref)
38UTS_MACHINE := mips 38UTS_MACHINE := mips
39endif 39endif
40ifdef CONFIG_64BIT 40ifdef CONFIG_64BIT
41tool-prefix = $(64bit-tool-prefix) 41tool-archpref = $(64bit-tool-archpref)
42UTS_MACHINE := mips64 42UTS_MACHINE := mips64
43endif 43endif
44 44
45ifdef CONFIG_CROSSCOMPILE 45ifneq ($(SUBARCH),$(ARCH))
46CROSS_COMPILE := $(tool-prefix) 46 ifeq ($(CROSS_COMPILE),)
47 CROSS_COMPILE := $(call cc-cross-prefix, $(tool-archpref)-linux- $(tool-archpref)-gnu-linux- $(tool-archpref)-unknown-gnu-linux-)
48 endif
47endif 49endif
48 50
49ifdef CONFIG_32BIT 51ifdef CONFIG_32BIT
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index 6b83f4ddc8fc..d73833b7c781 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the Cobalt micro systems family specific parts of the kernel 2# Makefile for the Cobalt micro systems family specific parts of the kernel
3# 3#
4 4
5obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o 5obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o time.o
6 6
7obj-$(CONFIG_PCI) += pci.o 7obj-$(CONFIG_PCI) += pci.o
8obj-$(CONFIG_EARLY_PRINTK) += console.o 8obj-$(CONFIG_EARLY_PRINTK) += console.o
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index d11bb1bc7b6b..dd23beb8604f 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -9,19 +9,17 @@
9 * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv) 9 * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
10 * 10 *
11 */ 11 */
12#include <linux/interrupt.h>
13#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/io.h>
15#include <linux/ioport.h>
14#include <linux/pm.h> 16#include <linux/pm.h>
15 17
16#include <asm/bootinfo.h> 18#include <asm/bootinfo.h>
17#include <asm/time.h>
18#include <asm/i8253.h>
19#include <asm/io.h>
20#include <asm/reboot.h> 19#include <asm/reboot.h>
21#include <asm/gt64120.h> 20#include <asm/gt64120.h>
22 21
23#include <cobalt.h> 22#include <cobalt.h>
24#include <irq.h>
25 23
26extern void cobalt_machine_restart(char *command); 24extern void cobalt_machine_restart(char *command);
27extern void cobalt_machine_halt(void); 25extern void cobalt_machine_halt(void);
@@ -41,17 +39,6 @@ const char *get_system_type(void)
41 return "MIPS Cobalt"; 39 return "MIPS Cobalt";
42} 40}
43 41
44void __init plat_timer_setup(struct irqaction *irq)
45{
46 /* Load timer value for HZ (TCLK is 50MHz) */
47 GT_WRITE(GT_TC0_OFS, 50*1000*1000 / HZ);
48
49 /* Enable timer0 */
50 GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
51
52 setup_irq(GT641XX_TIMER0_IRQ, irq);
53}
54
55/* 42/*
56 * Cobalt doesn't have PS/2 keyboard/mouse interfaces, 43 * Cobalt doesn't have PS/2 keyboard/mouse interfaces,
57 * keyboard conntroller is never used. 44 * keyboard conntroller is never used.
@@ -84,11 +71,6 @@ static struct resource cobalt_reserved_resources[] = {
84 }, 71 },
85}; 72};
86 73
87void __init plat_time_init(void)
88{
89 setup_pit_timer();
90}
91
92void __init plat_mem_setup(void) 74void __init plat_mem_setup(void)
93{ 75{
94 int i; 76 int i;
diff --git a/arch/mips/cobalt/time.c b/arch/mips/cobalt/time.c
new file mode 100644
index 000000000000..fa819fccd5db
--- /dev/null
+++ b/arch/mips/cobalt/time.c
@@ -0,0 +1,35 @@
1/*
2 * Cobalt time initialization.
3 *
4 * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <linux/init.h>
21
22#include <asm/gt64120.h>
23#include <asm/i8253.h>
24#include <asm/time.h>
25
26#define GT641XX_BASE_CLOCK 50000000 /* 50MHz */
27
28void __init plat_time_init(void)
29{
30 setup_pit_timer();
31
32 gt641xx_set_base_clock(GT641XX_BASE_CLOCK);
33
34 mips_timer_state = gt641xx_timer0_state;
35}
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index a3afa39faae5..d7745c8976f6 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -9,6 +9,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
9 time.o topology.o traps.o unaligned.o 9 time.o topology.o traps.o unaligned.o
10 10
11obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o 11obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o
12obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o
12 13
13binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ 14binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
14 irix5sys.o sysirix.o 15 irix5sys.o sysirix.o
diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c
new file mode 100644
index 000000000000..4c651b2680f9
--- /dev/null
+++ b/arch/mips/kernel/cevt-gt641xx.c
@@ -0,0 +1,144 @@
1/*
2 * GT641xx clockevent routines.
3 *
4 * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <linux/clockchips.h>
21#include <linux/init.h>
22#include <linux/interrupt.h>
23#include <linux/spinlock.h>
24
25#include <asm/gt64120.h>
26#include <asm/time.h>
27
28#include <irq.h>
29
30static DEFINE_SPINLOCK(gt641xx_timer_lock);
31static unsigned int gt641xx_base_clock;
32
33void gt641xx_set_base_clock(unsigned int clock)
34{
35 gt641xx_base_clock = clock;
36}
37
38int gt641xx_timer0_state(void)
39{
40 if (GT_READ(GT_TC0_OFS))
41 return 0;
42
43 GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
44 GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK);
45
46 return 1;
47}
48
49static int gt641xx_timer0_set_next_event(unsigned long delta,
50 struct clock_event_device *evt)
51{
52 unsigned long flags;
53 u32 ctrl;
54
55 spin_lock_irqsave(&gt641xx_timer_lock, flags);
56
57 ctrl = GT_READ(GT_TC_CONTROL_OFS);
58 ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
59 ctrl |= GT_TC_CONTROL_ENTC0_MSK;
60
61 GT_WRITE(GT_TC0_OFS, delta);
62 GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
63
64 spin_unlock_irqrestore(&gt641xx_timer_lock, flags);
65
66 return 0;
67}
68
69static void gt641xx_timer0_set_mode(enum clock_event_mode mode,
70 struct clock_event_device *evt)
71{
72 unsigned long flags;
73 u32 ctrl;
74
75 spin_lock_irqsave(&gt641xx_timer_lock, flags);
76
77 ctrl = GT_READ(GT_TC_CONTROL_OFS);
78 ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
79
80 switch (mode) {
81 case CLOCK_EVT_MODE_PERIODIC:
82 ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK;
83 break;
84 case CLOCK_EVT_MODE_ONESHOT:
85 ctrl |= GT_TC_CONTROL_ENTC0_MSK;
86 break;
87 default:
88 break;
89 }
90
91 GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
92
93 spin_unlock_irqrestore(&gt641xx_timer_lock, flags);
94}
95
96static void gt641xx_timer0_event_handler(struct clock_event_device *dev)
97{
98}
99
100static struct clock_event_device gt641xx_timer0_clockevent = {
101 .name = "gt641xx-timer0",
102 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
103 .cpumask = CPU_MASK_CPU0,
104 .irq = GT641XX_TIMER0_IRQ,
105 .set_next_event = gt641xx_timer0_set_next_event,
106 .set_mode = gt641xx_timer0_set_mode,
107 .event_handler = gt641xx_timer0_event_handler,
108};
109
110static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
111{
112 struct clock_event_device *cd = &gt641xx_timer0_clockevent;
113
114 cd->event_handler(cd);
115
116 return IRQ_HANDLED;
117}
118
119static struct irqaction gt641xx_timer0_irqaction = {
120 .handler = gt641xx_timer0_interrupt,
121 .flags = IRQF_DISABLED | IRQF_PERCPU,
122 .name = "gt641xx_timer0",
123};
124
125static int __init gt641xx_timer0_clockevent_init(void)
126{
127 struct clock_event_device *cd;
128
129 if (!gt641xx_base_clock)
130 return 0;
131
132 GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
133
134 cd = &gt641xx_timer0_clockevent;
135 cd->rating = 200 + gt641xx_base_clock / 10000000;
136 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
137 cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
138 clockevent_set_clock(cd, gt641xx_base_clock);
139
140 clockevents_register_device(&gt641xx_timer0_clockevent);
141
142 return setup_irq(GT641XX_TIMER0_IRQ, &gt641xx_timer0_irqaction);
143}
144arch_initcall(gt641xx_timer0_clockevent_init);
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index a915e5693421..ae2984fff580 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -186,7 +186,7 @@ static int c0_compare_int_usable(void)
186 * IP7 already pending? Try to clear it by acking the timer. 186 * IP7 already pending? Try to clear it by acking the timer.
187 */ 187 */
188 if (c0_compare_int_pending()) { 188 if (c0_compare_int_pending()) {
189 write_c0_compare(read_c0_compare()); 189 write_c0_compare(read_c0_count());
190 irq_disable_hazard(); 190 irq_disable_hazard();
191 if (c0_compare_int_pending()) 191 if (c0_compare_int_pending())
192 return 0; 192 return 0;
@@ -202,7 +202,7 @@ static int c0_compare_int_usable(void)
202 if (!c0_compare_int_pending()) 202 if (!c0_compare_int_pending())
203 return 0; 203 return 0;
204 204
205 write_c0_compare(read_c0_compare()); 205 write_c0_compare(read_c0_count());
206 irq_disable_hazard(); 206 irq_disable_hazard();
207 if (c0_compare_int_pending()) 207 if (c0_compare_int_pending())
208 return 0; 208 return 0;
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index c4e6866d5cbc..6c6849a8f136 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -195,8 +195,8 @@ void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
195 195
196 /* Find a shift value */ 196 /* Find a shift value */
197 for (shift = 32; shift > 0; shift--) { 197 for (shift = 32; shift > 0; shift--) {
198 temp = (u64) NSEC_PER_SEC << shift; 198 temp = (u64) clock << shift;
199 do_div(temp, clock); 199 do_div(temp, NSEC_PER_SEC);
200 if ((temp >> 32) == 0) 200 if ((temp >> 32) == 0)
201 break; 201 break;
202 } 202 }
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 1d00b778ff1e..9d6243a8c15a 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -147,21 +147,8 @@ void __init plat_time_init(void)
147#endif 147#endif
148} 148}
149 149
150//static irqreturn_t mips_perf_interrupt(int irq, void *dev_id)
151//{
152// return perf_irq();
153//}
154
155//static struct irqaction perf_irqaction = {
156// .handler = mips_perf_interrupt,
157// .flags = IRQF_DISABLED | IRQF_PERCPU,
158// .name = "performance",
159//};
160
161void __init plat_perf_setup(void) 150void __init plat_perf_setup(void)
162{ 151{
163// struct irqaction *irq = &perf_irqaction;
164
165 cp0_perfcount_irq = -1; 152 cp0_perfcount_irq = -1;
166 153
167#ifdef MSC01E_INT_BASE 154#ifdef MSC01E_INT_BASE
diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index 681b593071cb..3305fa9ae66d 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -110,7 +110,7 @@ static void __init per_hub_init(cnodeid_t cnode)
110 } 110 }
111} 111}
112 112
113void __init per_cpu_init(void) 113void __cpuinit per_cpu_init(void)
114{ 114{
115 int cpu = smp_processor_id(); 115 int cpu = smp_processor_id();
116 int slice = LOCAL_HUB_L(PI_CPU_NUM); 116 int slice = LOCAL_HUB_L(PI_CPU_NUM);
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index d467bf4f6c3f..f5dccf01da11 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -111,8 +111,24 @@ unsigned long read_persistent_clock(void)
111 return mktime(year, month, date, hour, min, sec); 111 return mktime(year, month, date, hour, min, sec);
112} 112}
113 113
114static int rt_set_next_event(unsigned long delta, 114static void enable_rt_irq(unsigned int irq)
115 struct clock_event_device *evt) 115{
116}
117
118static void disable_rt_irq(unsigned int irq)
119{
120}
121
122static struct irq_chip rt_irq_type = {
123 .name = "SN HUB RT timer",
124 .ack = disable_rt_irq,
125 .mask = disable_rt_irq,
126 .mask_ack = disable_rt_irq,
127 .unmask = enable_rt_irq,
128 .eoi = enable_rt_irq,
129};
130
131static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
116{ 132{
117 unsigned int cpu = smp_processor_id(); 133 unsigned int cpu = smp_processor_id();
118 int slice = cputoslice(cpu) == 0; 134 int slice = cputoslice(cpu) == 0;
@@ -129,50 +145,24 @@ static void rt_set_mode(enum clock_event_mode mode,
129 struct clock_event_device *evt) 145 struct clock_event_device *evt)
130{ 146{
131 switch (mode) { 147 switch (mode) {
132 case CLOCK_EVT_MODE_PERIODIC: 148 case CLOCK_EVT_MODE_ONESHOT:
133 /* The only mode supported */ 149 /* The only mode supported */
134 break; 150 break;
135 151
152 case CLOCK_EVT_MODE_PERIODIC:
136 case CLOCK_EVT_MODE_UNUSED: 153 case CLOCK_EVT_MODE_UNUSED:
137 case CLOCK_EVT_MODE_SHUTDOWN: 154 case CLOCK_EVT_MODE_SHUTDOWN:
138 case CLOCK_EVT_MODE_ONESHOT:
139 case CLOCK_EVT_MODE_RESUME: 155 case CLOCK_EVT_MODE_RESUME:
140 /* Nothing to do */ 156 /* Nothing to do */
141 break; 157 break;
142 } 158 }
143} 159}
144 160
145struct clock_event_device rt_clock_event_device = {
146 .name = "HUB-RT",
147 .features = CLOCK_EVT_FEAT_ONESHOT,
148
149 .rating = 300,
150 .set_next_event = rt_set_next_event,
151 .set_mode = rt_set_mode,
152};
153
154static void enable_rt_irq(unsigned int irq)
155{
156}
157
158static void disable_rt_irq(unsigned int irq)
159{
160}
161
162static struct irq_chip rt_irq_type = {
163 .name = "SN HUB RT timer",
164 .ack = disable_rt_irq,
165 .mask = disable_rt_irq,
166 .mask_ack = disable_rt_irq,
167 .unmask = enable_rt_irq,
168 .eoi = enable_rt_irq,
169};
170
171unsigned int rt_timer_irq; 161unsigned int rt_timer_irq;
172 162
173static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id) 163static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
174{ 164{
175 struct clock_event_device *cd = &rt_clock_event_device; 165 struct clock_event_device *cd = dev_id;
176 unsigned int cpu = smp_processor_id(); 166 unsigned int cpu = smp_processor_id();
177 int slice = cputoslice(cpu) == 0; 167 int slice = cputoslice(cpu) == 0;
178 168
@@ -182,11 +172,10 @@ static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id)
182 return IRQ_HANDLED; 172 return IRQ_HANDLED;
183} 173}
184 174
185static struct irqaction rt_irqaction = { 175struct irqaction hub_rt_irqaction = {
186 .handler = (irq_handler_t) ip27_rt_timer_interrupt, 176 .handler = hub_rt_counter_handler,
187 .flags = IRQF_DISABLED, 177 .flags = IRQF_DISABLED | IRQF_PERCPU,
188 .mask = CPU_MASK_NONE, 178 .name = "hub-rt",
189 .name = "timer"
190}; 179};
191 180
192/* 181/*
@@ -200,32 +189,48 @@ static struct irqaction rt_irqaction = {
200#define NSEC_PER_CYCLE 800 189#define NSEC_PER_CYCLE 800
201#define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE) 190#define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE)
202 191
203static void __init ip27_rt_clock_event_init(void) 192static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
193static DEFINE_PER_CPU(char [11], hub_rt_name);
194
195static void __cpuinit hub_rt_clock_event_init(void)
204{ 196{
205 struct clock_event_device *cd = &rt_clock_event_device;
206 unsigned int cpu = smp_processor_id(); 197 unsigned int cpu = smp_processor_id();
207 int irq = allocate_irqno(); 198 struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
208 199 unsigned char *name = per_cpu(hub_rt_name, cpu);
209 if (irq < 0) 200 int irq = rt_timer_irq;
210 panic("Can't allocate interrupt number for timer interrupt"); 201
211 202 sprintf(name, "hub-rt %d", cpu);
212 rt_timer_irq = irq; 203 cd->name = "HUB-RT",
213 204 cd->features = CLOCK_EVT_FEAT_ONESHOT,
205 clockevent_set_clock(cd, CYCLES_PER_SEC);
206 cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd);
207 cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
208 cd->rating = 200,
214 cd->irq = irq, 209 cd->irq = irq,
215 cd->cpumask = cpumask_of_cpu(cpu), 210 cd->cpumask = cpumask_of_cpu(cpu),
216 211 cd->rating = 300,
217 /* 212 cd->set_next_event = rt_next_event,
218 * Calculate the min / max delta 213 cd->set_mode = rt_set_mode,
219 */
220 cd->mult =
221 div_sc((unsigned long) CYCLES_PER_SEC, NSEC_PER_SEC, 32);
222 cd->shift = 32;
223 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
224 cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
225 clockevents_register_device(cd); 214 clockevents_register_device(cd);
215}
216
217static void __init hub_rt_clock_event_global_init(void)
218{
219 unsigned int irq;
220
221 do {
222 smp_wmb();
223 irq = rt_timer_irq;
224 if (irq)
225 break;
226
227 irq = allocate_irqno();
228 if (irq < 0)
229 panic("Allocation of irq number for timer failed");
230 } while (xchg(&rt_timer_irq, irq));
226 231
227 set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq); 232 set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq);
228 setup_irq(irq, &rt_irqaction); 233 setup_irq(irq, &hub_rt_irqaction);
229} 234}
230 235
231static cycle_t hub_rt_read(void) 236static cycle_t hub_rt_read(void)
@@ -233,27 +238,29 @@ static cycle_t hub_rt_read(void)
233 return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); 238 return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
234} 239}
235 240
236struct clocksource ht_rt_clocksource = { 241struct clocksource hub_rt_clocksource = {
237 .name = "HUB-RT", 242 .name = "HUB-RT",
238 .rating = 200, 243 .rating = 200,
239 .read = hub_rt_read, 244 .read = hub_rt_read,
240 .mask = CLOCKSOURCE_MASK(52), 245 .mask = CLOCKSOURCE_MASK(52),
241 .shift = 32,
242 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 246 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
243}; 247};
244 248
245static void __init ip27_rt_clocksource_init(void) 249static void __init hub_rt_clocksource_init(void)
246{ 250{
247 clocksource_register(&ht_rt_clocksource); 251 struct clocksource *cs = &hub_rt_clocksource;
252
253 clocksource_set_clock(cs, CYCLES_PER_SEC);
254 clocksource_register(cs);
248} 255}
249 256
250void __init plat_time_init(void) 257void __init plat_time_init(void)
251{ 258{
252 ip27_rt_clock_event_init(); 259 hub_rt_clocksource_init();
253 ip27_rt_clocksource_init(); 260 hub_rt_clock_event_global_init();
254} 261}
255 262
256void __init cpu_time_init(void) 263void __cpuinit cpu_time_init(void)
257{ 264{
258 lboard_t *board; 265 lboard_t *board;
259 klcpu_t *cpu; 266 klcpu_t *cpu;
@@ -271,6 +278,7 @@ void __init cpu_time_init(void)
271 278
272 printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); 279 printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
273 280
281 hub_rt_clock_event_init();
274 set_c0_status(SRB_TIMOCLK); 282 set_c0_status(SRB_TIMOCLK);
275} 283}
276 284
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index 7aa79bf63c4a..10299bafeab7 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -452,6 +452,43 @@ static void bcm1480_kgdb_interrupt(void)
452 452
453extern void bcm1480_mailbox_interrupt(void); 453extern void bcm1480_mailbox_interrupt(void);
454 454
455static inline void dispatch_ip4(void)
456{
457 int cpu = smp_processor_id();
458 int irq = K_BCM1480_INT_TIMER_0 + cpu;
459
460 /* Reset the timer */
461 __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
462 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
463
464 do_IRQ(irq);
465}
466
467static inline void dispatch_ip2(void)
468{
469 unsigned long long mask_h, mask_l;
470 unsigned int cpu = smp_processor_id();
471 unsigned long base;
472
473 /*
474 * Default...we've hit an IP[2] interrupt, which means we've got to
475 * check the 1480 interrupt registers to figure out what to do. Need
476 * to detect which CPU we're on, now that smp_affinity is supported.
477 */
478 base = A_BCM1480_IMR_MAPPER(cpu);
479 mask_h = __raw_readq(
480 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
481 mask_l = __raw_readq(
482 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
483
484 if (mask_h) {
485 if (mask_h ^ 1)
486 do_IRQ(fls64(mask_h) - 1);
487 else if (mask_l)
488 do_IRQ(63 + fls64(mask_l));
489 }
490}
491
455asmlinkage void plat_irq_dispatch(void) 492asmlinkage void plat_irq_dispatch(void)
456{ 493{
457 unsigned int pending; 494 unsigned int pending;
@@ -469,17 +506,8 @@ asmlinkage void plat_irq_dispatch(void)
469 else 506 else
470#endif 507#endif
471 508
472 if (pending & CAUSEF_IP4) { 509 if (pending & CAUSEF_IP4)
473 int cpu = smp_processor_id(); 510 dispatch_ip4();
474 int irq = K_BCM1480_INT_TIMER_0 + cpu;
475
476 /* Reset the timer */
477 __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
478 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
479
480 do_IRQ(irq);
481 }
482
483#ifdef CONFIG_SMP 511#ifdef CONFIG_SMP
484 else if (pending & CAUSEF_IP3) 512 else if (pending & CAUSEF_IP3)
485 bcm1480_mailbox_interrupt(); 513 bcm1480_mailbox_interrupt();
@@ -490,27 +518,6 @@ asmlinkage void plat_irq_dispatch(void)
490 bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */ 518 bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */
491#endif 519#endif
492 520
493 else if (pending & CAUSEF_IP2) { 521 else if (pending & CAUSEF_IP2)
494 unsigned long long mask_h, mask_l; 522 dispatch_ip2();
495 unsigned long base;
496
497 /*
498 * Default...we've hit an IP[2] interrupt, which means we've
499 * got to check the 1480 interrupt registers to figure out what
500 * to do. Need to detect which CPU we're on, now that
501 * smp_affinity is supported.
502 */
503 base = A_BCM1480_IMR_MAPPER(smp_processor_id());
504 mask_h = __raw_readq(
505 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
506 mask_l = __raw_readq(
507 IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
508
509 if (mask_h) {
510 if (mask_h ^ 1)
511 do_IRQ(fls64(mask_h) - 1);
512 else
513 do_IRQ(63 + fls64(mask_l));
514 }
515 }
516} 523}
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
index 02b266a31c46..436ba78359ab 100644
--- a/arch/mips/sibyte/bcm1480/smp.c
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -58,7 +58,7 @@ static void *mailbox_0_regs[] = {
58/* 58/*
59 * SMP init and finish on secondary CPUs 59 * SMP init and finish on secondary CPUs
60 */ 60 */
61void bcm1480_smp_init(void) 61void __cpuinit bcm1480_smp_init(void)
62{ 62{
63 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | 63 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
64 STATUSF_IP1 | STATUSF_IP0; 64 STATUSF_IP1 | STATUSF_IP0;
@@ -67,7 +67,7 @@ void bcm1480_smp_init(void)
67 change_c0_status(ST0_IM, imask); 67 change_c0_status(ST0_IM, imask);
68} 68}
69 69
70void bcm1480_smp_finish(void) 70void __cpuinit bcm1480_smp_finish(void)
71{ 71{
72 extern void sb1480_clockevent_init(void); 72 extern void sb1480_clockevent_init(void);
73 73
diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c
index c730744aa474..610f0253954d 100644
--- a/arch/mips/sibyte/bcm1480/time.c
+++ b/arch/mips/sibyte/bcm1480/time.c
@@ -15,22 +15,12 @@
15 * along with this program; if not, write to the Free Software 15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */ 17 */
18
19/*
20 * These are routines to set up and handle interrupts from the
21 * bcm1480 general purpose timer 0. We're using the timer as a
22 * system clock, so we set it up to run at 100 Hz. On every
23 * interrupt, we update our idea of what the time of day is,
24 * then call do_timer() in the architecture-independent kernel
25 * code to do general bookkeeping (e.g. update jiffies, run
26 * bottom halves, etc.)
27 */
28#include <linux/clockchips.h> 18#include <linux/clockchips.h>
29#include <linux/interrupt.h> 19#include <linux/interrupt.h>
20#include <linux/irq.h>
30#include <linux/percpu.h> 21#include <linux/percpu.h>
31#include <linux/spinlock.h> 22#include <linux/spinlock.h>
32 23
33#include <asm/irq.h>
34#include <asm/addrspace.h> 24#include <asm/addrspace.h>
35#include <asm/time.h> 25#include <asm/time.h>
36#include <asm/io.h> 26#include <asm/io.h>
@@ -47,33 +37,10 @@
47#define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 37#define IMR_IP3_VAL K_BCM1480_INT_MAP_I1
48#define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 38#define IMR_IP4_VAL K_BCM1480_INT_MAP_I2
49 39
50#ifdef CONFIG_SIMULATION
51#define BCM1480_HPT_VALUE 50000
52#else
53#define BCM1480_HPT_VALUE 1000000
54#endif
55
56extern int bcm1480_steal_irq(int irq); 40extern int bcm1480_steal_irq(int irq);
57 41
58void __init plat_time_init(void)
59{
60 unsigned int cpu = smp_processor_id();
61 unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
62
63 BUG_ON(cpu > 3); /* Only have 4 general purpose timers */
64
65 bcm1480_mask_irq(cpu, irq);
66
67 /* Map the timer interrupt to ip[4] of this cpu */
68 __raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H)
69 + (irq<<3)));
70
71 bcm1480_unmask_irq(cpu, irq);
72 bcm1480_steal_irq(irq);
73}
74
75/* 42/*
76 * The general purpose timer ticks at 1 Mhz independent if 43 * The general purpose timer ticks at 1MHz independent if
77 * the rest of the system 44 * the rest of the system
78 */ 45 */
79static void sibyte_set_mode(enum clock_event_mode mode, 46static void sibyte_set_mode(enum clock_event_mode mode,
@@ -88,7 +55,7 @@ static void sibyte_set_mode(enum clock_event_mode mode,
88 switch (mode) { 55 switch (mode) {
89 case CLOCK_EVT_MODE_PERIODIC: 56 case CLOCK_EVT_MODE_PERIODIC:
90 __raw_writeq(0, timer_cfg); 57 __raw_writeq(0, timer_cfg);
91 __raw_writeq(BCM1480_HPT_VALUE / HZ - 1, timer_init); 58 __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init);
92 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 59 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
93 timer_cfg); 60 timer_cfg);
94 break; 61 break;
@@ -121,80 +88,96 @@ static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd)
121 return res; 88 return res;
122} 89}
123 90
124static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
125
126static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) 91static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
127{ 92{
128 unsigned int cpu = smp_processor_id(); 93 unsigned int cpu = smp_processor_id();
129 struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); 94 struct clock_event_device *cd = dev_id;
95 void __iomem *timer_cfg;
96
97 timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
130 98
131 /* Reset the timer */ 99 /* Reset the timer */
132 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 100 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
133 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); 101 timer_cfg);
134 cd->event_handler(cd); 102 cd->event_handler(cd);
135 103
136 return IRQ_HANDLED; 104 return IRQ_HANDLED;
137} 105}
138 106
139static struct irqaction sibyte_counter_irqaction = { 107static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
140 .handler = sibyte_counter_handler, 108static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
141 .flags = IRQF_DISABLED | IRQF_PERCPU, 109static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
142 .name = "timer",
143};
144 110
145/*
146 * This interrupt is "special" in that it doesn't use the request_irq
147 * way to hook the irq line. The timer interrupt is initialized early
148 * enough to make this a major pain, and it's also firing enough to
149 * warrant a bit of special case code. bcm1480_timer_interrupt is
150 * called directly from irq_handler.S when IP[4] is set during an
151 * interrupt
152 */
153void __cpuinit sb1480_clockevent_init(void) 111void __cpuinit sb1480_clockevent_init(void)
154{ 112{
155 unsigned int cpu = smp_processor_id(); 113 unsigned int cpu = smp_processor_id();
156 unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; 114 unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
115 struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
157 struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); 116 struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
117 unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
118
119 BUG_ON(cpu > 3); /* Only have 4 general purpose timers */
158 120
159 cd->name = "bcm1480-counter"; 121 sprintf(name, "bcm1480-counter %d", cpu);
122 cd->name = name;
160 cd->features = CLOCK_EVT_FEAT_PERIODIC | 123 cd->features = CLOCK_EVT_FEAT_PERIODIC |
161 CLOCK_EVT_MODE_ONESHOT; 124 CLOCK_EVT_MODE_ONESHOT;
125 clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
126 cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
127 cd->min_delta_ns = clockevent_delta2ns(1, cd);
128 cd->rating = 200;
129 cd->irq = irq;
130 cd->cpumask = cpumask_of_cpu(cpu);
162 cd->set_next_event = sibyte_next_event; 131 cd->set_next_event = sibyte_next_event;
163 cd->set_mode = sibyte_set_mode; 132 cd->set_mode = sibyte_set_mode;
164 cd->irq = irq; 133 clockevents_register_device(cd);
165 clockevent_set_clock(cd, BCM1480_HPT_VALUE); 134
135 bcm1480_mask_irq(cpu, irq);
136
137 /*
138 * Map timer interrupt to IP[4] of this cpu
139 */
140 __raw_writeq(IMR_IP4_VAL,
141 IOADDR(A_BCM1480_IMR_REGISTER(cpu,
142 R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (irq << 3)));
166 143
167 setup_irq(irq, &sibyte_counter_irqaction); 144 bcm1480_unmask_irq(cpu, irq);
145 bcm1480_steal_irq(irq);
146
147 action->handler = sibyte_counter_handler;
148 action->flags = IRQF_DISABLED | IRQF_PERCPU;
149 action->name = name;
150 action->dev_id = cd;
151 setup_irq(irq, action);
168} 152}
169 153
170static cycle_t bcm1480_hpt_read(void) 154static cycle_t bcm1480_hpt_read(void)
171{ 155{
172 /* We assume this function is called xtime_lock held. */ 156 return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT));
173 unsigned long count =
174 __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT)));
175 return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count;
176} 157}
177 158
178struct clocksource bcm1480_clocksource = { 159struct clocksource bcm1480_clocksource = {
179 .name = "MIPS", 160 .name = "zbbus-cycles",
180 .rating = 200, 161 .rating = 200,
181 .read = bcm1480_hpt_read, 162 .read = bcm1480_hpt_read,
182 .mask = CLOCKSOURCE_MASK(32), 163 .mask = CLOCKSOURCE_MASK(64),
183 .shift = 32,
184 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 164 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
185}; 165};
186 166
187void __init sb1480_clocksource_init(void) 167void __init sb1480_clocksource_init(void)
188{ 168{
189 struct clocksource *cs = &bcm1480_clocksource; 169 struct clocksource *cs = &bcm1480_clocksource;
170 unsigned int plldiv;
171 unsigned long zbbus;
190 172
191 clocksource_set_clock(cs, BCM1480_HPT_VALUE); 173 plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
174 zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000);
175 clocksource_set_clock(cs, zbbus);
192 clocksource_register(cs); 176 clocksource_register(cs);
193} 177}
194 178
195void __init bcm1480_hpt_setup(void) 179void __init plat_time_init(void)
196{ 180{
197 mips_hpt_frequency = BCM1480_HPT_VALUE;
198 sb1480_clocksource_init(); 181 sb1480_clocksource_init();
199 sb1480_clockevent_init(); 182 sb1480_clockevent_init();
200} 183}
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index 500d17e84c09..53780a179d1d 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -402,6 +402,22 @@ static void sb1250_kgdb_interrupt(void)
402 402
403extern void sb1250_mailbox_interrupt(void); 403extern void sb1250_mailbox_interrupt(void);
404 404
405static inline void dispatch_ip2(void)
406{
407 unsigned int cpu = smp_processor_id();
408 unsigned long long mask;
409
410 /*
411 * Default...we've hit an IP[2] interrupt, which means we've got to
412 * check the 1250 interrupt registers to figure out what to do. Need
413 * to detect which CPU we're on, now that smp_affinity is supported.
414 */
415 mask = __raw_readq(IOADDR(A_IMR_REGISTER(cpu,
416 R_IMR_INTERRUPT_STATUS_BASE)));
417 if (mask)
418 do_IRQ(fls64(mask) - 1);
419}
420
405asmlinkage void plat_irq_dispatch(void) 421asmlinkage void plat_irq_dispatch(void)
406{ 422{
407 unsigned int cpu = smp_processor_id(); 423 unsigned int cpu = smp_processor_id();
@@ -434,21 +450,8 @@ asmlinkage void plat_irq_dispatch(void)
434 sb1250_kgdb_interrupt(); 450 sb1250_kgdb_interrupt();
435#endif 451#endif
436 452
437 else if (pending & CAUSEF_IP2) { 453 else if (pending & CAUSEF_IP2)
438 unsigned long long mask; 454 dispatch_ip2();
439 455 else
440 /*
441 * Default...we've hit an IP[2] interrupt, which means we've
442 * got to check the 1250 interrupt registers to figure out what
443 * to do. Need to detect which CPU we're on, now that
444 * smp_affinity is supported.
445 */
446 mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
447 R_IMR_INTERRUPT_STATUS_BASE)));
448 if (mask)
449 do_IRQ(fls64(mask) - 1);
450 else
451 spurious_interrupt();
452 } else
453 spurious_interrupt(); 456 spurious_interrupt();
454} 457}
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
index aaa4f30dda79..3f52c95a4eb8 100644
--- a/arch/mips/sibyte/sb1250/smp.c
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -46,7 +46,7 @@ static void *mailbox_regs[] = {
46/* 46/*
47 * SMP init and finish on secondary CPUs 47 * SMP init and finish on secondary CPUs
48 */ 48 */
49void sb1250_smp_init(void) 49void __cpuinit sb1250_smp_init(void)
50{ 50{
51 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | 51 unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
52 STATUSF_IP1 | STATUSF_IP0; 52 STATUSF_IP1 | STATUSF_IP0;
@@ -55,7 +55,7 @@ void sb1250_smp_init(void)
55 change_c0_status(ST0_IM, imask); 55 change_c0_status(ST0_IM, imask);
56} 56}
57 57
58void sb1250_smp_finish(void) 58void __cpuinit sb1250_smp_finish(void)
59{ 59{
60 extern void sb1250_clockevent_init(void); 60 extern void sb1250_clockevent_init(void);
61 61
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
index 9ef54628bc9c..a41e908bc218 100644
--- a/arch/mips/sibyte/sb1250/time.c
+++ b/arch/mips/sibyte/sb1250/time.c
@@ -52,26 +52,6 @@
52 52
53extern int sb1250_steal_irq(int irq); 53extern int sb1250_steal_irq(int irq);
54 54
55static cycle_t sb1250_hpt_read(void);
56
57void __init sb1250_hpt_setup(void)
58{
59 int cpu = smp_processor_id();
60
61 if (!cpu) {
62 /* Setup hpt using timer #3 but do not enable irq for it */
63 __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
64 __raw_writeq(SB1250_HPT_VALUE,
65 IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT)));
66 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
67 IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
68
69 mips_hpt_frequency = V_SCD_TIMER_FREQ;
70 clocksource_mips.read = sb1250_hpt_read;
71 clocksource_mips.mask = M_SCD_TIMER_INIT;
72 }
73}
74
75/* 55/*
76 * The general purpose timer ticks at 1 Mhz independent if 56 * The general purpose timer ticks at 1 Mhz independent if
77 * the rest of the system 57 * the rest of the system
@@ -121,18 +101,14 @@ sibyte_next_event(unsigned long delta, struct clock_event_device *evt)
121 return 0; 101 return 0;
122} 102}
123 103
124struct clock_event_device sibyte_hpt_clockevent = {
125 .name = "sb1250-counter",
126 .features = CLOCK_EVT_FEAT_PERIODIC,
127 .set_mode = sibyte_set_mode,
128 .set_next_event = sibyte_next_event,
129 .shift = 32,
130 .irq = 0,
131};
132
133static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) 104static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
134{ 105{
135 struct clock_event_device *cd = &sibyte_hpt_clockevent; 106 unsigned int cpu = smp_processor_id();
107 struct clock_event_device *cd = dev_id;
108
109 /* ACK interrupt */
110 ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
111 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
136 112
137 cd->event_handler(cd); 113 cd->event_handler(cd);
138 114
@@ -145,15 +121,35 @@ static struct irqaction sibyte_irqaction = {
145 .name = "timer", 121 .name = "timer",
146}; 122};
147 123
124static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
125static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
126static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
127
148void __cpuinit sb1250_clockevent_init(void) 128void __cpuinit sb1250_clockevent_init(void)
149{ 129{
150 struct clock_event_device *cd = &sibyte_hpt_clockevent;
151 unsigned int cpu = smp_processor_id(); 130 unsigned int cpu = smp_processor_id();
152 int irq = K_INT_TIMER_0 + cpu; 131 unsigned int irq = K_INT_TIMER_0 + cpu;
132 struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
133 struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
134 unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
153 135
154 /* Only have 4 general purpose timers, and we use last one as hpt */ 136 /* Only have 4 general purpose timers, and we use last one as hpt */
155 BUG_ON(cpu > 2); 137 BUG_ON(cpu > 2);
156 138
139 sprintf(name, "bcm1480-counter %d", cpu);
140 cd->name = name;
141 cd->features = CLOCK_EVT_FEAT_PERIODIC |
142 CLOCK_EVT_MODE_ONESHOT;
143 clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
144 cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
145 cd->min_delta_ns = clockevent_delta2ns(1, cd);
146 cd->rating = 200;
147 cd->irq = irq;
148 cd->cpumask = cpumask_of_cpu(cpu);
149 cd->set_next_event = sibyte_next_event;
150 cd->set_mode = sibyte_set_mode;
151 clockevents_register_device(cd);
152
157 sb1250_mask_irq(cpu, irq); 153 sb1250_mask_irq(cpu, irq);
158 154
159 /* Map the timer interrupt to ip[4] of this cpu */ 155 /* Map the timer interrupt to ip[4] of this cpu */
@@ -165,17 +161,11 @@ void __cpuinit sb1250_clockevent_init(void)
165 sb1250_unmask_irq(cpu, irq); 161 sb1250_unmask_irq(cpu, irq);
166 sb1250_steal_irq(irq); 162 sb1250_steal_irq(irq);
167 163
168 /* 164 action->handler = sibyte_counter_handler;
169 * This interrupt is "special" in that it doesn't use the request_irq 165 action->flags = IRQF_DISABLED | IRQF_PERCPU;
170 * way to hook the irq line. The timer interrupt is initialized early 166 action->name = name;
171 * enough to make this a major pain, and it's also firing enough to 167 action->dev_id = cd;
172 * warrant a bit of special case code. sb1250_timer_interrupt is
173 * called directly from irq_handler.S when IP[4] is set during an
174 * interrupt
175 */
176 setup_irq(irq, &sibyte_irqaction); 168 setup_irq(irq, &sibyte_irqaction);
177
178 clockevents_register_device(cd);
179} 169}
180 170
181/* 171/*
@@ -195,8 +185,7 @@ struct clocksource bcm1250_clocksource = {
195 .name = "MIPS", 185 .name = "MIPS",
196 .rating = 200, 186 .rating = 200,
197 .read = sb1250_hpt_read, 187 .read = sb1250_hpt_read,
198 .mask = CLOCKSOURCE_MASK(32), 188 .mask = CLOCKSOURCE_MASK(23),
199 .shift = 32,
200 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 189 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
201}; 190};
202 191
@@ -204,6 +193,17 @@ void __init sb1250_clocksource_init(void)
204{ 193{
205 struct clocksource *cs = &bcm1250_clocksource; 194 struct clocksource *cs = &bcm1250_clocksource;
206 195
196 /* Setup hpt using timer #3 but do not enable irq for it */
197 __raw_writeq(0,
198 IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
199 R_SCD_TIMER_CFG)));
200 __raw_writeq(SB1250_HPT_VALUE,
201 IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
202 R_SCD_TIMER_INIT)));
203 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
204 IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
205 R_SCD_TIMER_CFG)));
206
207 clocksource_set_clock(cs, V_SCD_TIMER_FREQ); 207 clocksource_set_clock(cs, V_SCD_TIMER_FREQ);
208 clocksource_register(cs); 208 clocksource_register(cs);
209} 209}