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/mips/sibyte | |
| parent | 9b9ea2202f3396790f635c62f7498ad75f08f62c (diff) | |
[MIPS] Clockevent driver for BCM1480
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/sibyte')
| -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 | } |
