1/* 2 * 3 * Copyright (C) 2001 MontaVista Software, ppopov@mvista.com 4 * Copied and modified Carsten Langgaard's time.c 5 * 6 * Carsten Langgaard, carstenl@mips.com 7 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. 8 * 9 * ######################################################################## 10 * 11 * This program is free software; you can distribute it and/or modify it 12 * under the terms of the GNU General Public License (Version 2) as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 * for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with this program; if not, write to the Free Software Foundation, Inc., 22 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 23 * 24 * ######################################################################## 25 * 26 * Setting up the clock on the MIPS boards. 27 * 28 * Update. Always configure the kernel with CONFIG_NEW_TIME_C. This 29 * will use the user interface gettimeofday() functions from the 30 * arch/mips/kernel/time.c, and we provide the clock interrupt processing 31 * and the timer offset compute functions. If CONFIG_PM is selected, 32 * we also ensure the 32KHz timer is available. -- Dan 33 */ 34 35#include <linux/types.h> 36#include <linux/init.h> 37#include <linux/kernel_stat.h> 38#include <linux/sched.h> 39#include <linux/spinlock.h> 40#include <linux/hardirq.h> 41 42#include <asm/compiler.h> 43#include <asm/mipsregs.h> 44#include <asm/time.h> 45#include <asm/div64.h> 46#include <asm/mach-au1x00/au1000.h> 47 48#include <linux/mc146818rtc.h> 49#include <linux/timex.h> 50 51static unsigned long r4k_offset; /* Amount to increment compare reg each time */ 52static unsigned long r4k_cur; /* What counter should be at next timer irq */ 53int no_au1xxx_32khz; 54extern int allow_au1k_wait; /* default off for CP0 Counter */ 55 56#ifdef CONFIG_PM 57#if HZ < 100 || HZ > 1000 58#error "unsupported HZ value! Must be in [100,1000]" 59#endif 60#define MATCH20_INC (328*100/HZ) /* magic number 328 is for HZ=100... */ 61extern void startup_match20_interrupt(irq_handler_t handler); 62static unsigned long last_pc0, last_match20; 63#endif 64 65static DEFINE_SPINLOCK(time_lock); 66 67static inline void ack_r4ktimer(unsigned long newval) 68{ 69 write_c0_compare(newval); 70} 71 72/* 73 * There are a lot of conceptually broken versions of the MIPS timer interrupt 74 * handler floating around. This one is rather different, but the algorithm 75 * is provably more robust. 76 */ 77unsigned long wtimer; 78 79void mips_timer_interrupt(void) 80{ 81 int irq = 63; 82 83 irq_enter(); 84 kstat_this_cpu.irqs[irq]++; 85 86 if (r4k_offset == 0) 87 goto null; 88 89 do { 90 kstat_this_cpu.irqs[irq]++; 91 do_timer(1); 92#ifndef CONFIG_SMP 93 update_process_times(user_mode(get_irq_regs())); 94#endif 95 r4k_cur += r4k_offset; 96 ack_r4ktimer(r4k_cur); 97 98 } while (((unsigned long)read_c0_count() 99 - r4k_cur) < 0x7fffffff); 100 101 irq_exit(); 102 return; 103 104null: 105 ack_r4ktimer(0); 106 irq_exit(); 107} 108 109#ifdef CONFIG_PM 110irqreturn_t counter0_irq(int irq, void *dev_id) 111{ 112 unsigned long pc0; 113 int time_elapsed; 114 static int jiffie_drift = 0; 115 116 if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) { 117 /* should never happen! */ 118 printk(KERN_WARNING "counter 0 w status error\n"); 119 return IRQ_NONE; 120 } 121 122 pc0 = au_readl(SYS_TOYREAD); 123 if (pc0 < last_match20) { 124 /* counter overflowed */ 125 time_elapsed = (0xffffffff - last_match20) + pc0; 126 } 127 else { 128 time_elapsed = pc0 - last_match20; 129 } 130 131 while (time_elapsed > 0) { 132 do_timer(1); 133#ifndef CONFIG_SMP 134 update_process_times(user_mode(get_irq_regs())); 135#endif 136 time_elapsed -= MATCH20_INC; 137 last_match20 += MATCH20_INC; 138 jiffie_drift++; 139 } 140 141 last_pc0 = pc0; 142 au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); 143 au_sync(); 144 145 /* our counter ticks at 10.009765625 ms/tick, we we're running 146 * almost 10uS too slow per tick. 147 */ 148 149 if (jiffie_drift >= 999) { 150 jiffie_drift -= 999; 151 do_timer(1); /* increment jiffies by one */ 152#ifndef CONFIG_SMP 153 update_process_times(user_mode(get_irq_regs())); 154#endif 155 } 156 157 return IRQ_HANDLED; 158} 159 160/* When we wakeup from sleep, we have to "catch up" on all of the 161 * timer ticks we have missed. 162 */ 163void 164wakeup_counter0_adjust(void) 165{ 166 unsigned long pc0; 167 int time_elapsed; 168 169 pc0 = au_readl(SYS_TOYREAD); 170 if (pc0 < last_match20) { 171 /* counter overflowed */ 172 time_elapsed = (0xffffffff - last_match20) + pc0; 173 } 174 else { 175 time_elapsed = pc0 - last_match20; 176 } 177 178 while (time_elapsed > 0) { 179 time_elapsed -= MATCH20_INC; 180 last_match20 += MATCH20_INC; 181 } 182 183 last_pc0 = pc0; 184 au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); 185 au_sync(); 186 187} 188 189/* This is just for debugging to set the timer for a sleep delay. 190*/ 191void 192wakeup_counter0_set(int ticks) 193{ 194 unsigned long pc0; 195 196 pc0 = au_readl(SYS_TOYREAD); 197 last_pc0 = pc0; 198 au_writel(last_match20 + (MATCH20_INC * ticks), SYS_TOYMATCH2); 199 au_sync(); 200} 201#endif 202 203/* I haven't found anyone that doesn't use a 12 MHz source clock, 204 * but just in case..... 205 */ 206#ifdef CONFIG_AU1000_SRC_CLK 207#define AU1000_SRC_CLK CONFIG_AU1000_SRC_CLK 208#else 209#define AU1000_SRC_CLK 12000000 210#endif 211 212/* 213 * We read the real processor speed from the PLL. This is important 214 * because it is more accurate than computing it from the 32KHz 215 * counter, if it exists. If we don't have an accurate processor 216 * speed, all of the peripherals that derive their clocks based on 217 * this advertised speed will introduce error and sometimes not work 218 * properly. This function is futher convoluted to still allow configurations 219 * to do that in case they have really, really old silicon with a 220 * write-only PLL register, that we need the 32KHz when power management 221 * "wait" is enabled, and we need to detect if the 32KHz isn't present 222 * but requested......got it? :-) -- Dan 223 */ 224unsigned long cal_r4koff(void) 225{ 226 unsigned long cpu_speed; 227 unsigned long flags; 228 unsigned long counter; 229 230 spin_lock_irqsave(&time_lock, flags); 231 232 /* Power management cares if we don't have a 32KHz counter. 233 */ 234 no_au1xxx_32khz = 0; 235 counter = au_readl(SYS_COUNTER_CNTRL); 236 if (counter & SYS_CNTRL_E0) { 237 int trim_divide = 16; 238 239 au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL); 240 241 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); 242 /* RTC now ticks at 32.768/16 kHz */ 243 au_writel(trim_divide-1, SYS_RTCTRIM); 244 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S); 245 246 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); 247 au_writel (0, SYS_TOYWRITE); 248 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S); 249 250#if defined(CONFIG_AU1000_USE32K) 251 { 252 unsigned long start, end, count; 253 254 start = au_readl(SYS_RTCREAD); 255 start += 2; 256 /* wait for the beginning of a new tick 257 */ 258 while (au_readl(SYS_RTCREAD) < start); 259 260 /* Start r4k counter. 261 */ 262 write_c0_count(0); 263 264 /* Wait 0.5 seconds. 265 */ 266 end = start + (32768 / trim_divide)/2; 267 268 while (end > au_readl(SYS_RTCREAD)); 269 270 count = read_c0_count(); 271 cpu_speed = count * 2; 272 } 273#else 274 cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * 275 AU1000_SRC_CLK; 276#endif 277 } 278 else { 279 /* The 32KHz oscillator isn't running, so assume there 280 * isn't one and grab the processor speed from the PLL. 281 * NOTE: some old silicon doesn't allow reading the PLL. 282 */ 283 cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK; 284 no_au1xxx_32khz = 1; 285 } 286 mips_hpt_frequency = cpu_speed; 287 // Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) 288 set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16)); 289 spin_unlock_irqrestore(&time_lock, flags); 290 return (cpu_speed / HZ); 291} 292 293void __init plat_timer_setup(struct irqaction *irq) 294{ 295 unsigned int est_freq; 296 297 printk("calculating r4koff... "); 298 r4k_offset = cal_r4koff(); 299 printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); 300 301 //est_freq = 2*r4k_offset*HZ; 302 est_freq = r4k_offset*HZ; 303 est_freq += 5000; /* round */ 304 est_freq -= est_freq%10000; 305 printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, 306 (est_freq%1000000)*100/1000000); 307 set_au1x00_speed(est_freq); 308 set_au1x00_lcd_clock(); // program the LCD clock 309 310 r4k_cur = (read_c0_count() + r4k_offset); 311 write_c0_compare(r4k_cur); 312 313#ifdef CONFIG_PM 314 /* 315 * setup counter 0, since it keeps ticking after a 316 * 'wait' instruction has been executed. The CP0 timer and 317 * counter 1 do NOT continue running after 'wait' 318 * 319 * It's too early to call request_irq() here, so we handle 320 * counter 0 interrupt as a special irq and it doesn't show 321 * up under /proc/interrupts. 322 * 323 * Check to ensure we really have a 32KHz oscillator before 324 * we do this. 325 */ 326 if (no_au1xxx_32khz) { 327 unsigned int c0_status; 328 329 printk("WARNING: no 32KHz clock found.\n"); 330 331 /* Ensure we get CPO_COUNTER interrupts. 332 */ 333 c0_status = read_c0_status(); 334 c0_status |= IE_IRQ5; 335 write_c0_status(c0_status); 336 } 337 else { 338 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); 339 au_writel(0, SYS_TOYWRITE); 340 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S); 341 342 au_writel(au_readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK); 343 au_writel(~0, SYS_WAKESRC); 344 au_sync(); 345 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); 346 347 /* setup match20 to interrupt once every HZ */ 348 last_pc0 = last_match20 = au_readl(SYS_TOYREAD); 349 au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2); 350 au_sync(); 351 while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); 352 startup_match20_interrupt(counter0_irq); 353 354 /* We can use the real 'wait' instruction. 355 */ 356 allow_au1k_wait = 1; 357 } 358 359#endif 360} 361 362void __init au1xxx_time_init(void) 363{ 364} 365