aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-ixp2000/core.c34
-rw-r--r--drivers/char/watchdog/ixp2000_wdt.c7
-rw-r--r--include/asm-arm/arch-ixp2000/ixp2000-regs.h1
3 files changed, 33 insertions, 9 deletions
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 4f3c3d5c781c..fc0555596d6d 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -162,12 +162,13 @@ void __init ixp2000_map_io(void)
162static unsigned ticks_per_jiffy; 162static unsigned ticks_per_jiffy;
163static unsigned ticks_per_usec; 163static unsigned ticks_per_usec;
164static unsigned next_jiffy_time; 164static unsigned next_jiffy_time;
165static volatile unsigned long *missing_jiffy_timer_csr;
165 166
166unsigned long ixp2000_gettimeoffset (void) 167unsigned long ixp2000_gettimeoffset (void)
167{ 168{
168 unsigned long offset; 169 unsigned long offset;
169 170
170 offset = next_jiffy_time - *IXP2000_T4_CSR; 171 offset = next_jiffy_time - *missing_jiffy_timer_csr;
171 172
172 return offset / ticks_per_usec; 173 return offset / ticks_per_usec;
173} 174}
@@ -179,7 +180,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
179 /* clear timer 1 */ 180 /* clear timer 1 */
180 ixp2000_reg_write(IXP2000_T1_CLR, 1); 181 ixp2000_reg_write(IXP2000_T1_CLR, 1);
181 182
182 while ((next_jiffy_time - *IXP2000_T4_CSR) > ticks_per_jiffy) { 183 while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) {
183 timer_tick(regs); 184 timer_tick(regs);
184 next_jiffy_time -= ticks_per_jiffy; 185 next_jiffy_time -= ticks_per_jiffy;
185 } 186 }
@@ -197,20 +198,37 @@ static struct irqaction ixp2000_timer_irq = {
197 198
198void __init ixp2000_init_time(unsigned long tick_rate) 199void __init ixp2000_init_time(unsigned long tick_rate)
199{ 200{
200 ixp2000_reg_write(IXP2000_T1_CLR, 0);
201 ixp2000_reg_write(IXP2000_T4_CLR, 0);
202
203 ticks_per_jiffy = (tick_rate + HZ/2) / HZ; 201 ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
204 ticks_per_usec = tick_rate / 1000000; 202 ticks_per_usec = tick_rate / 1000000;
205 203
204 /*
205 * We use timer 1 as our timer interrupt.
206 */
207 ixp2000_reg_write(IXP2000_T1_CLR, 0);
206 ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1); 208 ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1);
207 ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7)); 209 ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7));
208 210
209 /* 211 /*
210 * We use T4 as a monotonic counter to track missed jiffies 212 * We use a second timer as a monotonic counter for tracking
213 * missed jiffies. The IXP2000 has four timers, but if we're
214 * on an A-step IXP2800, timer 2 and 3 don't work, so on those
215 * chips we use timer 4. Timer 4 is the only timer that can
216 * be used for the watchdog, so we use timer 2 if we're on a
217 * non-buggy chip.
211 */ 218 */
212 ixp2000_reg_write(IXP2000_T4_CLD, -1); 219 if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
213 ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); 220 printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n");
221
222 ixp2000_reg_write(IXP2000_T4_CLR, 0);
223 ixp2000_reg_write(IXP2000_T4_CLD, -1);
224 ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7));
225 missing_jiffy_timer_csr = IXP2000_T4_CSR;
226 } else {
227 ixp2000_reg_write(IXP2000_T2_CLR, 0);
228 ixp2000_reg_write(IXP2000_T2_CLD, -1);
229 ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7));
230 missing_jiffy_timer_csr = IXP2000_T2_CSR;
231 }
214 next_jiffy_time = 0xffffffff; 232 next_jiffy_time = 0xffffffff;
215 233
216 /* register for interrupt */ 234 /* register for interrupt */
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
index ab659d37b4d2..4e98c215e5b1 100644
--- a/drivers/char/watchdog/ixp2000_wdt.c
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -192,7 +192,12 @@ static struct miscdevice ixp2000_wdt_miscdev =
192 192
193static int __init ixp2000_wdt_init(void) 193static int __init ixp2000_wdt_init(void)
194{ 194{
195 wdt_tick_rate = (*IXP2000_T1_CLD * HZ)/ 256;; 195 if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
196 printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n");
197 return -EIO;
198 }
199
200 wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
196 201
197 return misc_register(&ixp2000_wdt_miscdev); 202 return misc_register(&ixp2000_wdt_miscdev);
198} 203}
diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
index 6c56708d0ff0..a1d9e181b10f 100644
--- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h
+++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
@@ -363,6 +363,7 @@
363#define IXP2000_MIN_REV_MASK 0x0000000F 363#define IXP2000_MIN_REV_MASK 0x0000000F
364#define IXP2000_PROD_ID_MASK 0xFFFFFFFF 364#define IXP2000_PROD_ID_MASK 0xFFFFFFFF
365 365
366#define IXP2000_PRODUCT_ID GLOBAL_REG(0x00)
366#define IXP2000_MISC_CONTROL GLOBAL_REG(0x04) 367#define IXP2000_MISC_CONTROL GLOBAL_REG(0x04)
367#define IXP2000_MSF_CLK_CNTRL GLOBAL_REG(0x08) 368#define IXP2000_MSF_CLK_CNTRL GLOBAL_REG(0x08)
368#define IXP2000_RESET0 GLOBAL_REG(0x0c) 369#define IXP2000_RESET0 GLOBAL_REG(0x0c)