aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
parentfaf2782bf3903391936aba0b575fd39b1da10d00 (diff)
[MIPS] Sibyte: Fixes for oneshot timer mode.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/sibyte/bcm1480/time.c51
-rw-r--r--arch/mips/sibyte/sb1250/time.c66
2 files changed, 55 insertions, 62 deletions
diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c
index 39e77d9bd94..2bcaf5419ac 100644
--- a/arch/mips/sibyte/bcm1480/time.c
+++ b/arch/mips/sibyte/bcm1480/time.c
@@ -17,13 +17,11 @@
17 */ 17 */
18#include <linux/clockchips.h> 18#include <linux/clockchips.h>
19#include <linux/interrupt.h> 19#include <linux/interrupt.h>
20#include <linux/irq.h>
21#include <linux/percpu.h> 20#include <linux/percpu.h>
22#include <linux/spinlock.h>
23 21
24#include <asm/addrspace.h> 22#include <asm/addrspace.h>
25#include <asm/time.h>
26#include <asm/io.h> 23#include <asm/io.h>
24#include <asm/time.h>
27 25
28#include <asm/sibyte/bcm1480_regs.h> 26#include <asm/sibyte/bcm1480_regs.h>
29#include <asm/sibyte/sb1250_regs.h> 27#include <asm/sibyte/sb1250_regs.h>
@@ -45,23 +43,23 @@ static void sibyte_set_mode(enum clock_event_mode mode,
45 struct clock_event_device *evt) 43 struct clock_event_device *evt)
46{ 44{
47 unsigned int cpu = smp_processor_id(); 45 unsigned int cpu = smp_processor_id();
48 void __iomem *timer_cfg, *timer_init; 46 void __iomem *cfg, *init;
49 47
50 timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); 48 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
51 timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); 49 init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT));
52 50
53 switch (mode) { 51 switch (mode) {
54 case CLOCK_EVT_MODE_PERIODIC: 52 case CLOCK_EVT_MODE_PERIODIC:
55 __raw_writeq(0, timer_cfg); 53 __raw_writeq(0, cfg);
56 __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init); 54 __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init);
57 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 55 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
58 timer_cfg); 56 cfg);
59 break; 57 break;
60 58
61 case CLOCK_EVT_MODE_ONESHOT: 59 case CLOCK_EVT_MODE_ONESHOT:
62 /* Stop the timer until we actually program a shot */ 60 /* Stop the timer until we actually program a shot */
63 case CLOCK_EVT_MODE_SHUTDOWN: 61 case CLOCK_EVT_MODE_SHUTDOWN:
64 __raw_writeq(0, timer_cfg); 62 __raw_writeq(0, cfg);
65 break; 63 break;
66 64
67 case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ 65 case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */
@@ -73,30 +71,33 @@ static void sibyte_set_mode(enum clock_event_mode mode,
73static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) 71static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd)
74{ 72{
75 unsigned int cpu = smp_processor_id(); 73 unsigned int cpu = smp_processor_id();
76 void __iomem *timer_init; 74 void __iomem *cfg, *init;
77 unsigned int cnt;
78 int res;
79 75
80 timer_init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); 76 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
81 cnt = __raw_readq(timer_init); 77 init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT));
82 cnt += delta;
83 __raw_writeq(cnt, timer_init);
84 res = ((long)(__raw_readq(timer_init) - cnt ) > 0) ? -ETIME : 0;
85 78
86 return res; 79 __raw_writeq(delta - 1, init);
80 __raw_writeq(M_SCD_TIMER_ENABLE, cfg);
81
82 return 0;
87} 83}
88 84
89static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) 85static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
90{ 86{
91 unsigned int cpu = smp_processor_id(); 87 unsigned int cpu = smp_processor_id();
92 struct clock_event_device *cd = dev_id; 88 struct clock_event_device *cd = dev_id;
93 void __iomem *timer_cfg; 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;
94 96
95 timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); 97 /* ACK interrupt */
98 cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
99 ____raw_writeq(tmode, cfg);
96 100
97 /* Reset the timer */
98 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
99 timer_cfg);
100 cd->event_handler(cd); 101 cd->event_handler(cd);
101 102
102 return IRQ_HANDLED; 103 return IRQ_HANDLED;
@@ -133,7 +134,7 @@ void __cpuinit sb1480_clockevent_init(void)
133 bcm1480_mask_irq(cpu, irq); 134 bcm1480_mask_irq(cpu, irq);
134 135
135 /* 136 /*
136 * Map timer interrupt to IP[4] of this cpu 137 * Map the timer interrupt to IP[4] of this cpu
137 */ 138 */
138 __raw_writeq(IMR_IP4_VAL, 139 __raw_writeq(IMR_IP4_VAL,
139 IOADDR(A_BCM1480_IMR_REGISTER(cpu, 140 IOADDR(A_BCM1480_IMR_REGISTER(cpu,
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
index f455ac12a21..24b9c8bad62 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)));