aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sibyte/sb1250
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-10-31 20:24:50 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-11-02 12:13:47 -0400
commitf3f9ad0edcc1b7bf154bb34fe3b3f71e5379c9f0 (patch)
treed553ebebfad8bf083342e6af704ae62ae252d0f2 /arch/mips/sibyte/sb1250
parentfaf2782bf3903391936aba0b575fd39b1da10d00 (diff)
[MIPS] Sibyte: Fixes for oneshot timer mode.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/sibyte/sb1250')
-rw-r--r--arch/mips/sibyte/sb1250/time.c66
1 files changed, 29 insertions, 37 deletions
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
index f455ac12a210..24b9c8bad62f 100644
--- a/arch/mips/sibyte/sb1250/time.c
+++ b/arch/mips/sibyte/sb1250/time.c
@@ -15,33 +15,19 @@
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 * sb1250 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>
30#include <linux/sched.h> 20#include <linux/percpu.h>
31#include <linux/spinlock.h>
32#include <linux/kernel_stat.h>
33 21
34#include <asm/irq.h>
35#include <asm/addrspace.h> 22#include <asm/addrspace.h>
36#include <asm/time.h>
37#include <asm/io.h> 23#include <asm/io.h>
24#include <asm/time.h>
38 25
39#include <asm/sibyte/sb1250.h> 26#include <asm/sibyte/sb1250.h>
40#include <asm/sibyte/sb1250_regs.h> 27#include <asm/sibyte/sb1250_regs.h>
41#include <asm/sibyte/sb1250_int.h> 28#include <asm/sibyte/sb1250_int.h>
42#include <asm/sibyte/sb1250_scd.h> 29#include <asm/sibyte/sb1250_scd.h>
43 30
44
45#define IMR_IP2_VAL K_INT_MAP_I0 31#define IMR_IP2_VAL K_INT_MAP_I0
46#define IMR_IP3_VAL K_INT_MAP_I1 32#define IMR_IP3_VAL K_INT_MAP_I1
47#define IMR_IP4_VAL K_INT_MAP_I2 33#define IMR_IP4_VAL K_INT_MAP_I2
@@ -49,32 +35,31 @@
49#define SB1250_HPT_NUM 3 35#define SB1250_HPT_NUM 3
50#define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */ 36#define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */
51 37
52
53/* 38/*
54 * The general purpose timer ticks at 1 Mhz independent if 39 * The general purpose timer ticks at 1MHz independent if
55 * the rest of the system 40 * the rest of the system
56 */ 41 */
57static void sibyte_set_mode(enum clock_event_mode mode, 42static void sibyte_set_mode(enum clock_event_mode mode,
58 struct clock_event_device *evt) 43 struct clock_event_device *evt)
59{ 44{
60 unsigned int cpu = smp_processor_id(); 45 unsigned int cpu = smp_processor_id();
61 void __iomem *timer_cfg, *timer_init; 46 void __iomem *cfg, *init;
62 47
63 timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); 48 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
64 timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); 49 init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT));
65 50
66 switch(mode) { 51 switch (mode) {
67 case CLOCK_EVT_MODE_PERIODIC: 52 case CLOCK_EVT_MODE_PERIODIC:
68 __raw_writeq(0, timer_cfg); 53 __raw_writeq(0, cfg);
69 __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init); 54 __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init);
70 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 55 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
71 timer_cfg); 56 cfg);
72 break; 57 break;
73 58
74 case CLOCK_EVT_MODE_ONESHOT: 59 case CLOCK_EVT_MODE_ONESHOT:
75 /* Stop the timer until we actually program a shot */ 60 /* Stop the timer until we actually program a shot */
76 case CLOCK_EVT_MODE_SHUTDOWN: 61 case CLOCK_EVT_MODE_SHUTDOWN:
77 __raw_writeq(0, timer_cfg); 62 __raw_writeq(0, cfg);
78 break; 63 break;
79 64
80 case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ 65 case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */
@@ -83,18 +68,16 @@ static void sibyte_set_mode(enum clock_event_mode mode,
83 } 68 }
84} 69}
85 70
86static int 71static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd)
87sibyte_next_event(unsigned long delta, struct clock_event_device *evt)
88{ 72{
89 unsigned int cpu = smp_processor_id(); 73 unsigned int cpu = smp_processor_id();
90 void __iomem *timer_cfg, *timer_init; 74 void __iomem *cfg, *init;
91 75
92 timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); 76 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
93 timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); 77 init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT));
94 78
95 __raw_writeq(0, timer_cfg); 79 __raw_writeq(delta - 1, init);
96 __raw_writeq(delta, timer_init); 80 __raw_writeq(M_SCD_TIMER_ENABLE, cfg);
97 __raw_writeq(M_SCD_TIMER_ENABLE, timer_cfg);
98 81
99 return 0; 82 return 0;
100} 83}
@@ -103,10 +86,17 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
103{ 86{
104 unsigned int cpu = smp_processor_id(); 87 unsigned int cpu = smp_processor_id();
105 struct clock_event_device *cd = dev_id; 88 struct clock_event_device *cd = dev_id;
89 void __iomem *cfg;
90 unsigned long tmode;
91
92 if (cd->mode == CLOCK_EVT_MODE_PERIODIC)
93 tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS;
94 else
95 tmode = 0;
106 96
107 /* ACK interrupt */ 97 /* ACK interrupt */
108 ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 98 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
109 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); 99 ____raw_writeq(tmode, cfg);
110 100
111 cd->event_handler(cd); 101 cd->event_handler(cd);
112 102
@@ -144,7 +134,9 @@ void __cpuinit sb1250_clockevent_init(void)
144 134
145 sb1250_mask_irq(cpu, irq); 135 sb1250_mask_irq(cpu, irq);
146 136
147 /* Map the timer interrupt to ip[4] of this cpu */ 137 /*
138 * Map the timer interrupt to IP[4] of this cpu
139 */
148 __raw_writeq(IMR_IP4_VAL, 140 __raw_writeq(IMR_IP4_VAL,
149 IOADDR(A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) + 141 IOADDR(A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) +
150 (irq << 3))); 142 (irq << 3)));