aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sibyte/sb1250/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/sibyte/sb1250/time.c')
-rw-r--r--arch/mips/sibyte/sb1250/time.c73
1 files changed, 56 insertions, 17 deletions
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
index adc0b5271a06..1588f6debd90 100644
--- a/arch/mips/sibyte/sb1250/time.c
+++ b/arch/mips/sibyte/sb1250/time.c
@@ -47,23 +47,51 @@
47#define IMR_IP3_VAL K_INT_MAP_I1 47#define IMR_IP3_VAL K_INT_MAP_I1
48#define IMR_IP4_VAL K_INT_MAP_I2 48#define IMR_IP4_VAL K_INT_MAP_I2
49 49
50#define SB1250_HPT_NUM 3
51#define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */
52#define SB1250_HPT_SHIFT ((sizeof(unsigned int)*8)-V_SCD_TIMER_WIDTH)
53
54
50extern int sb1250_steal_irq(int irq); 55extern int sb1250_steal_irq(int irq);
51 56
57static unsigned int sb1250_hpt_read(void);
58static void sb1250_hpt_init(unsigned int);
59
60static unsigned int hpt_offset;
61
62void __init sb1250_hpt_setup(void)
63{
64 int cpu = smp_processor_id();
65
66 if (!cpu) {
67 /* Setup hpt using timer #3 but do not enable irq for it */
68 __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
69 __raw_writeq(SB1250_HPT_VALUE,
70 IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT)));
71 __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
72 IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
73
74 /*
75 * we need to fill 32 bits, so just use the upper 23 bits and pretend
76 * the timer is going 512Mhz instead of 1Mhz
77 */
78 mips_hpt_frequency = V_SCD_TIMER_FREQ << SB1250_HPT_SHIFT;
79 mips_hpt_init = sb1250_hpt_init;
80 mips_hpt_read = sb1250_hpt_read;
81 }
82}
83
84
52void sb1250_time_init(void) 85void sb1250_time_init(void)
53{ 86{
54 int cpu = smp_processor_id(); 87 int cpu = smp_processor_id();
55 int irq = K_INT_TIMER_0+cpu; 88 int irq = K_INT_TIMER_0+cpu;
56 89
57 /* Only have 4 general purpose timers */ 90 /* Only have 4 general purpose timers, and we use last one as hpt */
58 if (cpu > 3) { 91 if (cpu > 2) {
59 BUG(); 92 BUG();
60 } 93 }
61 94
62 if (!cpu) {
63 /* Use our own gettimeoffset() routine */
64 do_gettimeoffset = sb1250_gettimeoffset;
65 }
66
67 sb1250_mask_irq(cpu, irq); 95 sb1250_mask_irq(cpu, irq);
68 96
69 /* Map the timer interrupt to ip[4] of this cpu */ 97 /* Map the timer interrupt to ip[4] of this cpu */
@@ -103,7 +131,7 @@ void sb1250_timer_interrupt(struct pt_regs *regs)
103 int cpu = smp_processor_id(); 131 int cpu = smp_processor_id();
104 int irq = K_INT_TIMER_0 + cpu; 132 int irq = K_INT_TIMER_0 + cpu;
105 133
106 /* Reset the timer */ 134 /* ACK interrupt */
107 ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, 135 ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
108 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); 136 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
109 137
@@ -122,15 +150,26 @@ void sb1250_timer_interrupt(struct pt_regs *regs)
122} 150}
123 151
124/* 152/*
125 * We use our own do_gettimeoffset() instead of the generic one, 153 * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over
126 * because the generic one does not work for SMP case. 154 * again. There's no easy way to set to a specific value so store init value
127 * In addition, since we use general timer 0 for system time, 155 * in hpt_offset and subtract each time.
128 * we can get accurate intra-jiffy offset without calibration. 156 *
157 * Note: Timer isn't full 32bits so shift it into the upper part making
158 * it appear to run at a higher frequency.
129 */ 159 */
130unsigned long sb1250_gettimeoffset(void) 160static unsigned int sb1250_hpt_read(void)
131{ 161{
132 unsigned long count = 162 unsigned int count;
133 __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT)));
134 163
135 return 1000000/HZ - count; 164 count = G_SCD_TIMER_CNT(__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CNT))));
136 } 165
166 count = (SB1250_HPT_VALUE - count) << SB1250_HPT_SHIFT;
167
168 return count - hpt_offset;
169}
170
171static void sb1250_hpt_init(unsigned int count)
172{
173 hpt_offset = count;
174 return;
175}