diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-10-11 18:46:10 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-10-11 18:46:10 -0400 |
commit | e9f874b6f761f7f8394157d28641491c9babc1d3 (patch) | |
tree | 4f55da5f2c37e549c1ceb9de5e39869ae654f46a /arch | |
parent | 9b9ea2202f3396790f635c62f7498ad75f08f62c (diff) |
[MIPS] Clockevent driver for BCM1480
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/sibyte/bcm1480/time.c | 105 |
1 files changed, 80 insertions, 25 deletions
diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index 8519091d848b..40d7126cd5bf 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c | |||
@@ -25,6 +25,7 @@ | |||
25 | * code to do general bookkeeping (e.g. update jiffies, run | 25 | * code to do general bookkeeping (e.g. update jiffies, run |
26 | * bottom halves, etc.) | 26 | * bottom halves, etc.) |
27 | */ | 27 | */ |
28 | #include <linux/clockchips.h> | ||
28 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
29 | #include <linux/sched.h> | 30 | #include <linux/sched.h> |
30 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
@@ -55,15 +56,12 @@ | |||
55 | 56 | ||
56 | extern int bcm1480_steal_irq(int irq); | 57 | extern int bcm1480_steal_irq(int irq); |
57 | 58 | ||
58 | void bcm1480_time_init(void) | 59 | void __init plat_time_init(void) |
59 | { | 60 | { |
60 | int cpu = smp_processor_id(); | 61 | unsigned int cpu = smp_processor_id(); |
61 | int irq = K_BCM1480_INT_TIMER_0+cpu; | 62 | unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; |
62 | 63 | ||
63 | /* Only have 4 general purpose timers */ | 64 | BUG_ON(cpu > 3); /* Only have 4 general purpose timers */ |
64 | if (cpu > 3) { | ||
65 | BUG(); | ||
66 | } | ||
67 | 65 | ||
68 | bcm1480_mask_irq(cpu, irq); | 66 | bcm1480_mask_irq(cpu, irq); |
69 | 67 | ||
@@ -71,27 +69,83 @@ void bcm1480_time_init(void) | |||
71 | __raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) | 69 | __raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) |
72 | + (irq<<3))); | 70 | + (irq<<3))); |
73 | 71 | ||
74 | /* the general purpose timer ticks at 1 Mhz independent of the rest of the system */ | 72 | bcm1480_unmask_irq(cpu, irq); |
75 | /* Disable the timer and set up the count */ | 73 | bcm1480_steal_irq(irq); |
76 | __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); | 74 | } |
77 | __raw_writeq( | ||
78 | BCM1480_HPT_VALUE/HZ | ||
79 | , IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT))); | ||
80 | 75 | ||
81 | /* Set the timer running */ | 76 | /* |
77 | * The general purpose timer ticks at 1 Mhz independent if | ||
78 | * the rest of the system | ||
79 | */ | ||
80 | static void sibyte_set_mode(enum clock_event_mode mode, | ||
81 | struct clock_event_device *evt) | ||
82 | { | ||
83 | unsigned int cpu = smp_processor_id(); | ||
84 | void __iomem *timer_cfg, *timer_init; | ||
85 | |||
86 | timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); | ||
87 | timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); | ||
88 | |||
89 | switch (mode) { | ||
90 | case CLOCK_EVT_MODE_PERIODIC: | ||
91 | __raw_writeq(0, timer_cfg); | ||
92 | __raw_writeq(BCM1480_HPT_VALUE / HZ - 1, timer_init); | ||
93 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | ||
94 | timer_cfg); | ||
95 | break; | ||
96 | |||
97 | case CLOCK_EVT_MODE_ONESHOT: | ||
98 | /* Stop the timer until we actually program a shot */ | ||
99 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
100 | __raw_writeq(0, timer_cfg); | ||
101 | break; | ||
102 | |||
103 | case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ | ||
104 | ; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | struct clock_event_device sibyte_hpt_clockevent = { | ||
109 | .name = "bcm1480-counter", | ||
110 | .features = CLOCK_EVT_FEAT_PERIODIC, | ||
111 | .set_mode = sibyte_set_mode, | ||
112 | .shift = 32, | ||
113 | .irq = 0, | ||
114 | }; | ||
115 | |||
116 | static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) | ||
117 | { | ||
118 | struct clock_event_device *cd = &sibyte_hpt_clockevent; | ||
119 | unsigned int cpu = smp_processor_id(); | ||
120 | |||
121 | /* Reset the timer */ | ||
82 | __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, | 122 | __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, |
83 | IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); | 123 | IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); |
124 | cd->event_handler(cd); | ||
84 | 125 | ||
85 | bcm1480_unmask_irq(cpu, irq); | 126 | return IRQ_HANDLED; |
86 | bcm1480_steal_irq(irq); | 127 | } |
87 | /* | 128 | |
88 | * This interrupt is "special" in that it doesn't use the request_irq | 129 | static struct irqaction sibyte_counter_irqaction = { |
89 | * way to hook the irq line. The timer interrupt is initialized early | 130 | .handler = sibyte_counter_handler, |
90 | * enough to make this a major pain, and it's also firing enough to | 131 | .flags = IRQF_DISABLED | IRQF_PERCPU, |
91 | * warrant a bit of special case code. bcm1480_timer_interrupt is | 132 | .name = "timer", |
92 | * called directly from irq_handler.S when IP[4] is set during an | 133 | }; |
93 | * interrupt | 134 | |
94 | */ | 135 | /* |
136 | * This interrupt is "special" in that it doesn't use the request_irq | ||
137 | * way to hook the irq line. The timer interrupt is initialized early | ||
138 | * enough to make this a major pain, and it's also firing enough to | ||
139 | * warrant a bit of special case code. bcm1480_timer_interrupt is | ||
140 | * called directly from irq_handler.S when IP[4] is set during an | ||
141 | * interrupt | ||
142 | */ | ||
143 | static void __init sb1480_clockevent_init(void) | ||
144 | { | ||
145 | unsigned int cpu = smp_processor_id(); | ||
146 | unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; | ||
147 | |||
148 | setup_irq(irq, &sibyte_counter_irqaction); | ||
95 | } | 149 | } |
96 | 150 | ||
97 | void bcm1480_timer_interrupt(void) | 151 | void bcm1480_timer_interrupt(void) |
@@ -118,4 +172,5 @@ void __init bcm1480_hpt_setup(void) | |||
118 | { | 172 | { |
119 | clocksource_mips.read = bcm1480_hpt_read; | 173 | clocksource_mips.read = bcm1480_hpt_read; |
120 | mips_hpt_frequency = BCM1480_HPT_VALUE; | 174 | mips_hpt_frequency = BCM1480_HPT_VALUE; |
175 | sb1480_clockevent_init(); | ||
121 | } | 176 | } |