diff options
Diffstat (limited to 'arch/sparc/kernel/time_64.c')
| -rw-r--r-- | arch/sparc/kernel/time_64.c | 862 |
1 files changed, 862 insertions, 0 deletions
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c new file mode 100644 index 000000000000..141da3759091 --- /dev/null +++ b/arch/sparc/kernel/time_64.c | |||
| @@ -0,0 +1,862 @@ | |||
| 1 | /* time.c: UltraSparc timer and TOD clock support. | ||
| 2 | * | ||
| 3 | * Copyright (C) 1997, 2008 David S. Miller (davem@davemloft.net) | ||
| 4 | * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) | ||
| 5 | * | ||
| 6 | * Based largely on code which is: | ||
| 7 | * | ||
| 8 | * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/errno.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/sched.h> | ||
| 14 | #include <linux/smp_lock.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/param.h> | ||
| 17 | #include <linux/string.h> | ||
| 18 | #include <linux/mm.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/time.h> | ||
| 21 | #include <linux/timex.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/ioport.h> | ||
| 24 | #include <linux/mc146818rtc.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/profile.h> | ||
| 27 | #include <linux/bcd.h> | ||
| 28 | #include <linux/jiffies.h> | ||
| 29 | #include <linux/cpufreq.h> | ||
| 30 | #include <linux/percpu.h> | ||
| 31 | #include <linux/miscdevice.h> | ||
| 32 | #include <linux/rtc.h> | ||
| 33 | #include <linux/rtc/m48t59.h> | ||
| 34 | #include <linux/kernel_stat.h> | ||
| 35 | #include <linux/clockchips.h> | ||
| 36 | #include <linux/clocksource.h> | ||
| 37 | #include <linux/of_device.h> | ||
| 38 | #include <linux/platform_device.h> | ||
| 39 | |||
| 40 | #include <asm/oplib.h> | ||
| 41 | #include <asm/timer.h> | ||
| 42 | #include <asm/irq.h> | ||
| 43 | #include <asm/io.h> | ||
| 44 | #include <asm/prom.h> | ||
| 45 | #include <asm/starfire.h> | ||
| 46 | #include <asm/smp.h> | ||
| 47 | #include <asm/sections.h> | ||
| 48 | #include <asm/cpudata.h> | ||
| 49 | #include <asm/uaccess.h> | ||
| 50 | #include <asm/irq_regs.h> | ||
| 51 | |||
| 52 | #include "entry.h" | ||
| 53 | |||
| 54 | DEFINE_SPINLOCK(rtc_lock); | ||
| 55 | |||
| 56 | #define TICK_PRIV_BIT (1UL << 63) | ||
| 57 | #define TICKCMP_IRQ_BIT (1UL << 63) | ||
| 58 | |||
| 59 | #ifdef CONFIG_SMP | ||
| 60 | unsigned long profile_pc(struct pt_regs *regs) | ||
| 61 | { | ||
| 62 | unsigned long pc = instruction_pointer(regs); | ||
| 63 | |||
| 64 | if (in_lock_functions(pc)) | ||
| 65 | return regs->u_regs[UREG_RETPC]; | ||
| 66 | return pc; | ||
| 67 | } | ||
| 68 | EXPORT_SYMBOL(profile_pc); | ||
| 69 | #endif | ||
| 70 | |||
| 71 | static void tick_disable_protection(void) | ||
| 72 | { | ||
| 73 | /* Set things up so user can access tick register for profiling | ||
| 74 | * purposes. Also workaround BB_ERRATA_1 by doing a dummy | ||
| 75 | * read back of %tick after writing it. | ||
| 76 | */ | ||
| 77 | __asm__ __volatile__( | ||
| 78 | " ba,pt %%xcc, 1f\n" | ||
| 79 | " nop\n" | ||
| 80 | " .align 64\n" | ||
| 81 | "1: rd %%tick, %%g2\n" | ||
| 82 | " add %%g2, 6, %%g2\n" | ||
| 83 | " andn %%g2, %0, %%g2\n" | ||
| 84 | " wrpr %%g2, 0, %%tick\n" | ||
| 85 | " rdpr %%tick, %%g0" | ||
| 86 | : /* no outputs */ | ||
| 87 | : "r" (TICK_PRIV_BIT) | ||
| 88 | : "g2"); | ||
| 89 | } | ||
| 90 | |||
| 91 | static void tick_disable_irq(void) | ||
| 92 | { | ||
| 93 | __asm__ __volatile__( | ||
| 94 | " ba,pt %%xcc, 1f\n" | ||
| 95 | " nop\n" | ||
| 96 | " .align 64\n" | ||
| 97 | "1: wr %0, 0x0, %%tick_cmpr\n" | ||
| 98 | " rd %%tick_cmpr, %%g0" | ||
| 99 | : /* no outputs */ | ||
| 100 | : "r" (TICKCMP_IRQ_BIT)); | ||
| 101 | } | ||
| 102 | |||
| 103 | static void tick_init_tick(void) | ||
| 104 | { | ||
| 105 | tick_disable_protection(); | ||
| 106 | tick_disable_irq(); | ||
| 107 | } | ||
| 108 | |||
| 109 | static unsigned long tick_get_tick(void) | ||
| 110 | { | ||
| 111 | unsigned long ret; | ||
| 112 | |||
| 113 | __asm__ __volatile__("rd %%tick, %0\n\t" | ||
| 114 | "mov %0, %0" | ||
| 115 | : "=r" (ret)); | ||
| 116 | |||
| 117 | return ret & ~TICK_PRIV_BIT; | ||
| 118 | } | ||
| 119 | |||
| 120 | static int tick_add_compare(unsigned long adj) | ||
| 121 | { | ||
| 122 | unsigned long orig_tick, new_tick, new_compare; | ||
| 123 | |||
| 124 | __asm__ __volatile__("rd %%tick, %0" | ||
| 125 | : "=r" (orig_tick)); | ||
| 126 | |||
| 127 | orig_tick &= ~TICKCMP_IRQ_BIT; | ||
| 128 | |||
| 129 | /* Workaround for Spitfire Errata (#54 I think??), I discovered | ||
| 130 | * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch | ||
| 131 | * number 103640. | ||
| 132 | * | ||
| 133 | * On Blackbird writes to %tick_cmpr can fail, the | ||
| 134 | * workaround seems to be to execute the wr instruction | ||
| 135 | * at the start of an I-cache line, and perform a dummy | ||
| 136 | * read back from %tick_cmpr right after writing to it. -DaveM | ||
| 137 | */ | ||
| 138 | __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" | ||
| 139 | " add %1, %2, %0\n\t" | ||
| 140 | ".align 64\n" | ||
| 141 | "1:\n\t" | ||
| 142 | "wr %0, 0, %%tick_cmpr\n\t" | ||
| 143 | "rd %%tick_cmpr, %%g0\n\t" | ||
| 144 | : "=r" (new_compare) | ||
| 145 | : "r" (orig_tick), "r" (adj)); | ||
| 146 | |||
| 147 | __asm__ __volatile__("rd %%tick, %0" | ||
| 148 | : "=r" (new_tick)); | ||
| 149 | new_tick &= ~TICKCMP_IRQ_BIT; | ||
| 150 | |||
| 151 | return ((long)(new_tick - (orig_tick+adj))) > 0L; | ||
| 152 | } | ||
| 153 | |||
| 154 | static unsigned long tick_add_tick(unsigned long adj) | ||
| 155 | { | ||
| 156 | unsigned long new_tick; | ||
| 157 | |||
| 158 | /* Also need to handle Blackbird bug here too. */ | ||
| 159 | __asm__ __volatile__("rd %%tick, %0\n\t" | ||
| 160 | "add %0, %1, %0\n\t" | ||
| 161 | "wrpr %0, 0, %%tick\n\t" | ||
| 162 | : "=&r" (new_tick) | ||
| 163 | : "r" (adj)); | ||
| 164 | |||
| 165 | return new_tick; | ||
| 166 | } | ||
| 167 | |||
| 168 | static struct sparc64_tick_ops tick_operations __read_mostly = { | ||
| 169 | .name = "tick", | ||
| 170 | .init_tick = tick_init_tick, | ||
| 171 | .disable_irq = tick_disable_irq, | ||
| 172 | .get_tick = tick_get_tick, | ||
| 173 | .add_tick = tick_add_tick, | ||
| 174 | .add_compare = tick_add_compare, | ||
| 175 | .softint_mask = 1UL << 0, | ||
| 176 | }; | ||
| 177 | |||
| 178 | struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations; | ||
| 179 | |||
| 180 | static void stick_disable_irq(void) | ||
| 181 | { | ||
| 182 | __asm__ __volatile__( | ||
| 183 | "wr %0, 0x0, %%asr25" | ||
| 184 | : /* no outputs */ | ||
| 185 | : "r" (TICKCMP_IRQ_BIT)); | ||
| 186 | } | ||
| 187 | |||
| 188 | static void stick_init_tick(void) | ||
| 189 | { | ||
| 190 | /* Writes to the %tick and %stick register are not | ||
| 191 | * allowed on sun4v. The Hypervisor controls that | ||
| 192 | * bit, per-strand. | ||
| 193 | */ | ||
| 194 | if (tlb_type != hypervisor) { | ||
| 195 | tick_disable_protection(); | ||
| 196 | tick_disable_irq(); | ||
| 197 | |||
| 198 | /* Let the user get at STICK too. */ | ||
| 199 | __asm__ __volatile__( | ||
| 200 | " rd %%asr24, %%g2\n" | ||
| 201 | " andn %%g2, %0, %%g2\n" | ||
| 202 | " wr %%g2, 0, %%asr24" | ||
| 203 | : /* no outputs */ | ||
| 204 | : "r" (TICK_PRIV_BIT) | ||
| 205 | : "g1", "g2"); | ||
| 206 | } | ||
| 207 | |||
| 208 | stick_disable_irq(); | ||
| 209 | } | ||
| 210 | |||
| 211 | static unsigned long stick_get_tick(void) | ||
| 212 | { | ||
| 213 | unsigned long ret; | ||
| 214 | |||
| 215 | __asm__ __volatile__("rd %%asr24, %0" | ||
| 216 | : "=r" (ret)); | ||
| 217 | |||
| 218 | return ret & ~TICK_PRIV_BIT; | ||
| 219 | } | ||
| 220 | |||
| 221 | static unsigned long stick_add_tick(unsigned long adj) | ||
| 222 | { | ||
| 223 | unsigned long new_tick; | ||
| 224 | |||
| 225 | __asm__ __volatile__("rd %%asr24, %0\n\t" | ||
| 226 | "add %0, %1, %0\n\t" | ||
| 227 | "wr %0, 0, %%asr24\n\t" | ||
| 228 | : "=&r" (new_tick) | ||
| 229 | : "r" (adj)); | ||
| 230 | |||
| 231 | return new_tick; | ||
| 232 | } | ||
| 233 | |||
| 234 | static int stick_add_compare(unsigned long adj) | ||
| 235 | { | ||
| 236 | unsigned long orig_tick, new_tick; | ||
| 237 | |||
| 238 | __asm__ __volatile__("rd %%asr24, %0" | ||
| 239 | : "=r" (orig_tick)); | ||
| 240 | orig_tick &= ~TICKCMP_IRQ_BIT; | ||
| 241 | |||
| 242 | __asm__ __volatile__("wr %0, 0, %%asr25" | ||
| 243 | : /* no outputs */ | ||
| 244 | : "r" (orig_tick + adj)); | ||
| 245 | |||
| 246 | __asm__ __volatile__("rd %%asr24, %0" | ||
| 247 | : "=r" (new_tick)); | ||
| 248 | new_tick &= ~TICKCMP_IRQ_BIT; | ||
| 249 | |||
| 250 | return ((long)(new_tick - (orig_tick+adj))) > 0L; | ||
| 251 | } | ||
| 252 | |||
| 253 | static struct sparc64_tick_ops stick_operations __read_mostly = { | ||
| 254 | .name = "stick", | ||
| 255 | .init_tick = stick_init_tick, | ||
| 256 | .disable_irq = stick_disable_irq, | ||
| 257 | .get_tick = stick_get_tick, | ||
| 258 | .add_tick = stick_add_tick, | ||
| 259 | .add_compare = stick_add_compare, | ||
| 260 | .softint_mask = 1UL << 16, | ||
| 261 | }; | ||
| 262 | |||
| 263 | /* On Hummingbird the STICK/STICK_CMPR register is implemented | ||
| 264 | * in I/O space. There are two 64-bit registers each, the | ||
| 265 | * first holds the low 32-bits of the value and the second holds | ||
| 266 | * the high 32-bits. | ||
| 267 | * | ||
| 268 | * Since STICK is constantly updating, we have to access it carefully. | ||
| 269 | * | ||
| 270 | * The sequence we use to read is: | ||
| 271 | * 1) read high | ||
| 272 | * 2) read low | ||
| 273 | * 3) read high again, if it rolled re-read both low and high again. | ||
| 274 | * | ||
| 275 | * Writing STICK safely is also tricky: | ||
| 276 | * 1) write low to zero | ||
| 277 | * 2) write high | ||
| 278 | * 3) write low | ||
| 279 | */ | ||
| 280 | #define HBIRD_STICKCMP_ADDR 0x1fe0000f060UL | ||
| 281 | #define HBIRD_STICK_ADDR 0x1fe0000f070UL | ||
| 282 | |||
| 283 | static unsigned long __hbird_read_stick(void) | ||
| 284 | { | ||
| 285 | unsigned long ret, tmp1, tmp2, tmp3; | ||
| 286 | unsigned long addr = HBIRD_STICK_ADDR+8; | ||
| 287 | |||
| 288 | __asm__ __volatile__("ldxa [%1] %5, %2\n" | ||
| 289 | "1:\n\t" | ||
| 290 | "sub %1, 0x8, %1\n\t" | ||
| 291 | "ldxa [%1] %5, %3\n\t" | ||
| 292 | "add %1, 0x8, %1\n\t" | ||
| 293 | "ldxa [%1] %5, %4\n\t" | ||
| 294 | "cmp %4, %2\n\t" | ||
| 295 | "bne,a,pn %%xcc, 1b\n\t" | ||
| 296 | " mov %4, %2\n\t" | ||
| 297 | "sllx %4, 32, %4\n\t" | ||
| 298 | "or %3, %4, %0\n\t" | ||
| 299 | : "=&r" (ret), "=&r" (addr), | ||
| 300 | "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3) | ||
| 301 | : "i" (ASI_PHYS_BYPASS_EC_E), "1" (addr)); | ||
| 302 | |||
| 303 | return ret; | ||
| 304 | } | ||
| 305 | |||
| 306 | static void __hbird_write_stick(unsigned long val) | ||
| 307 | { | ||
| 308 | unsigned long low = (val & 0xffffffffUL); | ||
| 309 | unsigned long high = (val >> 32UL); | ||
| 310 | unsigned long addr = HBIRD_STICK_ADDR; | ||
| 311 | |||
| 312 | __asm__ __volatile__("stxa %%g0, [%0] %4\n\t" | ||
| 313 | "add %0, 0x8, %0\n\t" | ||
| 314 | "stxa %3, [%0] %4\n\t" | ||
| 315 | "sub %0, 0x8, %0\n\t" | ||
| 316 | "stxa %2, [%0] %4" | ||
| 317 | : "=&r" (addr) | ||
| 318 | : "0" (addr), "r" (low), "r" (high), | ||
| 319 | "i" (ASI_PHYS_BYPASS_EC_E)); | ||
| 320 | } | ||
| 321 | |||
| 322 | static void __hbird_write_compare(unsigned long val) | ||
| 323 | { | ||
| 324 | unsigned long low = (val & 0xffffffffUL); | ||
| 325 | unsigned long high = (val >> 32UL); | ||
| 326 | unsigned long addr = HBIRD_STICKCMP_ADDR + 0x8UL; | ||
| 327 | |||
| 328 | __asm__ __volatile__("stxa %3, [%0] %4\n\t" | ||
| 329 | "sub %0, 0x8, %0\n\t" | ||
| 330 | "stxa %2, [%0] %4" | ||
| 331 | : "=&r" (addr) | ||
| 332 | : "0" (addr), "r" (low), "r" (high), | ||
| 333 | "i" (ASI_PHYS_BYPASS_EC_E)); | ||
| 334 | } | ||
| 335 | |||
| 336 | static void hbtick_disable_irq(void) | ||
| 337 | { | ||
| 338 | __hbird_write_compare(TICKCMP_IRQ_BIT); | ||
| 339 | } | ||
| 340 | |||
| 341 | static void hbtick_init_tick(void) | ||
| 342 | { | ||
| 343 | tick_disable_protection(); | ||
| 344 | |||
| 345 | /* XXX This seems to be necessary to 'jumpstart' Hummingbird | ||
| 346 | * XXX into actually sending STICK interrupts. I think because | ||
| 347 | * XXX of how we store %tick_cmpr in head.S this somehow resets the | ||
| 348 | * XXX {TICK + STICK} interrupt mux. -DaveM | ||
| 349 | */ | ||
| 350 | __hbird_write_stick(__hbird_read_stick()); | ||
| 351 | |||
| 352 | hbtick_disable_irq(); | ||
| 353 | } | ||
| 354 | |||
| 355 | static unsigned long hbtick_get_tick(void) | ||
| 356 | { | ||
| 357 | return __hbird_read_stick() & ~TICK_PRIV_BIT; | ||
| 358 | } | ||
| 359 | |||
| 360 | static unsigned long hbtick_add_tick(unsigned long adj) | ||
| 361 | { | ||
| 362 | unsigned long val; | ||
| 363 | |||
| 364 | val = __hbird_read_stick() + adj; | ||
| 365 | __hbird_write_stick(val); | ||
| 366 | |||
| 367 | return val; | ||
| 368 | } | ||
| 369 | |||
| 370 | static int hbtick_add_compare(unsigned long adj) | ||
| 371 | { | ||
| 372 | unsigned long val = __hbird_read_stick(); | ||
| 373 | unsigned long val2; | ||
| 374 | |||
| 375 | val &= ~TICKCMP_IRQ_BIT; | ||
| 376 | val += adj; | ||
| 377 | __hbird_write_compare(val); | ||
| 378 | |||
| 379 | val2 = __hbird_read_stick() & ~TICKCMP_IRQ_BIT; | ||
| 380 | |||
| 381 | return ((long)(val2 - val)) > 0L; | ||
| 382 | } | ||
| 383 | |||
| 384 | static struct sparc64_tick_ops hbtick_operations __read_mostly = { | ||
| 385 | .name = "hbtick", | ||
| 386 | .init_tick = hbtick_init_tick, | ||
| 387 | .disable_irq = hbtick_disable_irq, | ||
| 388 | .get_tick = hbtick_get_tick, | ||
| 389 | .add_tick = hbtick_add_tick, | ||
| 390 | .add_compare = hbtick_add_compare, | ||
| 391 | .softint_mask = 1UL << 0, | ||
| 392 | }; | ||
| 393 | |||
| 394 | static unsigned long timer_ticks_per_nsec_quotient __read_mostly; | ||
| 395 | |||
| 396 | int update_persistent_clock(struct timespec now) | ||
| 397 | { | ||
| 398 | struct rtc_device *rtc = rtc_class_open("rtc0"); | ||
| 399 | int err = -1; | ||
| 400 | |||
| 401 | if (rtc) { | ||
| 402 | err = rtc_set_mmss(rtc, now.tv_sec); | ||
| 403 | rtc_class_close(rtc); | ||
| 404 | } | ||
| 405 | |||
| 406 | return err; | ||
| 407 | } | ||
| 408 | |||
| 409 | unsigned long cmos_regs; | ||
| 410 | EXPORT_SYMBOL(cmos_regs); | ||
| 411 | |||
| 412 | static struct resource rtc_cmos_resource; | ||
| 413 | |||
| 414 | static struct platform_device rtc_cmos_device = { | ||
| 415 | .name = "rtc_cmos", | ||
| 416 | .id = -1, | ||
| 417 | .resource = &rtc_cmos_resource, | ||
| 418 | .num_resources = 1, | ||
| 419 | }; | ||
| 420 | |||
| 421 | static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match) | ||
| 422 | { | ||
| 423 | struct resource *r; | ||
| 424 | |||
| 425 | printk(KERN_INFO "%s: RTC regs at 0x%lx\n", | ||
| 426 | op->node->full_name, op->resource[0].start); | ||
| 427 | |||
| 428 | /* The CMOS RTC driver only accepts IORESOURCE_IO, so cons | ||
| 429 | * up a fake resource so that the probe works for all cases. | ||
| 430 | * When the RTC is behind an ISA bus it will have IORESOURCE_IO | ||
| 431 | * already, whereas when it's behind EBUS is will be IORESOURCE_MEM. | ||
| 432 | */ | ||
| 433 | |||
| 434 | r = &rtc_cmos_resource; | ||
| 435 | r->flags = IORESOURCE_IO; | ||
| 436 | r->name = op->resource[0].name; | ||
| 437 | r->start = op->resource[0].start; | ||
| 438 | r->end = op->resource[0].end; | ||
| 439 | |||
| 440 | cmos_regs = op->resource[0].start; | ||
| 441 | return platform_device_register(&rtc_cmos_device); | ||
| 442 | } | ||
| 443 | |||
| 444 | static struct of_device_id __initdata rtc_match[] = { | ||
| 445 | { | ||
| 446 | .name = "rtc", | ||
| 447 | .compatible = "m5819", | ||
| 448 | }, | ||
| 449 | { | ||
| 450 | .name = "rtc", | ||
| 451 | .compatible = "isa-m5819p", | ||
| 452 | }, | ||
| 453 | { | ||
| 454 | .name = "rtc", | ||
| 455 | .compatible = "isa-m5823p", | ||
| 456 | }, | ||
| 457 | { | ||
| 458 | .name = "rtc", | ||
| 459 | .compatible = "ds1287", | ||
| 460 | }, | ||
| 461 | {}, | ||
| 462 | }; | ||
| 463 | |||
| 464 | static struct of_platform_driver rtc_driver = { | ||
| 465 | .match_table = rtc_match, | ||
| 466 | .probe = rtc_probe, | ||
| 467 | .driver = { | ||
| 468 | .name = "rtc", | ||
| 469 | }, | ||
| 470 | }; | ||
| 471 | |||
| 472 | static struct platform_device rtc_bq4802_device = { | ||
| 473 | .name = "rtc-bq4802", | ||
| 474 | .id = -1, | ||
| 475 | .num_resources = 1, | ||
| 476 | }; | ||
| 477 | |||
| 478 | static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match) | ||
| 479 | { | ||
| 480 | |||
| 481 | printk(KERN_INFO "%s: BQ4802 regs at 0x%lx\n", | ||
| 482 | op->node->full_name, op->resource[0].start); | ||
| 483 | |||
| 484 | rtc_bq4802_device.resource = &op->resource[0]; | ||
| 485 | return platform_device_register(&rtc_bq4802_device); | ||
| 486 | } | ||
| 487 | |||
| 488 | static struct of_device_id __initdata bq4802_match[] = { | ||
| 489 | { | ||
| 490 | .name = "rtc", | ||
| 491 | .compatible = "bq4802", | ||
| 492 | }, | ||
| 493 | {}, | ||
| 494 | }; | ||
| 495 | |||
| 496 | static struct of_platform_driver bq4802_driver = { | ||
| 497 | .match_table = bq4802_match, | ||
| 498 | .probe = bq4802_probe, | ||
| 499 | .driver = { | ||
| 500 | .name = "bq4802", | ||
| 501 | }, | ||
| 502 | }; | ||
| 503 | |||
| 504 | static unsigned char mostek_read_byte(struct device *dev, u32 ofs) | ||
| 505 | { | ||
| 506 | struct platform_device *pdev = to_platform_device(dev); | ||
| 507 | void __iomem *regs = (void __iomem *) pdev->resource[0].start; | ||
| 508 | |||
| 509 | return readb(regs + ofs); | ||
| 510 | } | ||
| 511 | |||
| 512 | static void mostek_write_byte(struct device *dev, u32 ofs, u8 val) | ||
| 513 | { | ||
| 514 | struct platform_device *pdev = to_platform_device(dev); | ||
| 515 | void __iomem *regs = (void __iomem *) pdev->resource[0].start; | ||
| 516 | |||
| 517 | writeb(val, regs + ofs); | ||
| 518 | } | ||
| 519 | |||
| 520 | static struct m48t59_plat_data m48t59_data = { | ||
| 521 | .read_byte = mostek_read_byte, | ||
| 522 | .write_byte = mostek_write_byte, | ||
| 523 | }; | ||
| 524 | |||
| 525 | static struct platform_device m48t59_rtc = { | ||
| 526 | .name = "rtc-m48t59", | ||
| 527 | .id = 0, | ||
| 528 | .num_resources = 1, | ||
| 529 | .dev = { | ||
| 530 | .platform_data = &m48t59_data, | ||
| 531 | }, | ||
| 532 | }; | ||
| 533 | |||
| 534 | static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match) | ||
| 535 | { | ||
| 536 | struct device_node *dp = op->node; | ||
| 537 | |||
| 538 | /* On an Enterprise system there can be multiple mostek clocks. | ||
| 539 | * We should only match the one that is on the central FHC bus. | ||
| 540 | */ | ||
| 541 | if (!strcmp(dp->parent->name, "fhc") && | ||
| 542 | strcmp(dp->parent->parent->name, "central") != 0) | ||
| 543 | return -ENODEV; | ||
| 544 | |||
| 545 | printk(KERN_INFO "%s: Mostek regs at 0x%lx\n", | ||
| 546 | dp->full_name, op->resource[0].start); | ||
| 547 | |||
| 548 | m48t59_rtc.resource = &op->resource[0]; | ||
| 549 | return platform_device_register(&m48t59_rtc); | ||
| 550 | } | ||
| 551 | |||
| 552 | static struct of_device_id __initdata mostek_match[] = { | ||
| 553 | { | ||
| 554 | .name = "eeprom", | ||
| 555 | }, | ||
| 556 | {}, | ||
| 557 | }; | ||
| 558 | |||
| 559 | static struct of_platform_driver mostek_driver = { | ||
| 560 | .match_table = mostek_match, | ||
| 561 | .probe = mostek_probe, | ||
| 562 | .driver = { | ||
| 563 | .name = "mostek", | ||
| 564 | }, | ||
| 565 | }; | ||
| 566 | |||
| 567 | static struct platform_device rtc_sun4v_device = { | ||
| 568 | .name = "rtc-sun4v", | ||
| 569 | .id = -1, | ||
| 570 | }; | ||
| 571 | |||
| 572 | static struct platform_device rtc_starfire_device = { | ||
| 573 | .name = "rtc-starfire", | ||
| 574 | .id = -1, | ||
| 575 | }; | ||
| 576 | |||
| 577 | static int __init clock_init(void) | ||
| 578 | { | ||
| 579 | if (this_is_starfire) | ||
| 580 | return platform_device_register(&rtc_starfire_device); | ||
| 581 | |||
| 582 | if (tlb_type == hypervisor) | ||
| 583 | return platform_device_register(&rtc_sun4v_device); | ||
| 584 | |||
| 585 | (void) of_register_driver(&rtc_driver, &of_platform_bus_type); | ||
| 586 | (void) of_register_driver(&mostek_driver, &of_platform_bus_type); | ||
| 587 | (void) of_register_driver(&bq4802_driver, &of_platform_bus_type); | ||
| 588 | |||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 592 | /* Must be after subsys_initcall() so that busses are probed. Must | ||
| 593 | * be before device_initcall() because things like the RTC driver | ||
| 594 | * need to see the clock registers. | ||
| 595 | */ | ||
| 596 | fs_initcall(clock_init); | ||
| 597 | |||
| 598 | /* This is gets the master TICK_INT timer going. */ | ||
| 599 | static unsigned long sparc64_init_timers(void) | ||
| 600 | { | ||
| 601 | struct device_node *dp; | ||
| 602 | unsigned long freq; | ||
| 603 | |||
| 604 | dp = of_find_node_by_path("/"); | ||
| 605 | if (tlb_type == spitfire) { | ||
| 606 | unsigned long ver, manuf, impl; | ||
| 607 | |||
| 608 | __asm__ __volatile__ ("rdpr %%ver, %0" | ||
| 609 | : "=&r" (ver)); | ||
| 610 | manuf = ((ver >> 48) & 0xffff); | ||
| 611 | impl = ((ver >> 32) & 0xffff); | ||
| 612 | if (manuf == 0x17 && impl == 0x13) { | ||
| 613 | /* Hummingbird, aka Ultra-IIe */ | ||
| 614 | tick_ops = &hbtick_operations; | ||
| 615 | freq = of_getintprop_default(dp, "stick-frequency", 0); | ||
| 616 | } else { | ||
| 617 | tick_ops = &tick_operations; | ||
| 618 | freq = local_cpu_data().clock_tick; | ||
| 619 | } | ||
| 620 | } else { | ||
| 621 | tick_ops = &stick_operations; | ||
| 622 | freq = of_getintprop_default(dp, "stick-frequency", 0); | ||
| 623 | } | ||
| 624 | |||
| 625 | return freq; | ||
| 626 | } | ||
| 627 | |||
| 628 | struct freq_table { | ||
| 629 | unsigned long clock_tick_ref; | ||
| 630 | unsigned int ref_freq; | ||
| 631 | }; | ||
| 632 | static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0 }; | ||
| 633 | |||
| 634 | unsigned long sparc64_get_clock_tick(unsigned int cpu) | ||
| 635 | { | ||
| 636 | struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu); | ||
| 637 | |||
| 638 | if (ft->clock_tick_ref) | ||
| 639 | return ft->clock_tick_ref; | ||
| 640 | return cpu_data(cpu).clock_tick; | ||
| 641 | } | ||
| 642 | |||
| 643 | #ifdef CONFIG_CPU_FREQ | ||
| 644 | |||
| 645 | static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val, | ||
| 646 | void *data) | ||
| 647 | { | ||
| 648 | struct cpufreq_freqs *freq = data; | ||
| 649 | unsigned int cpu = freq->cpu; | ||
| 650 | struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu); | ||
| 651 | |||
| 652 | if (!ft->ref_freq) { | ||
| 653 | ft->ref_freq = freq->old; | ||
| 654 | ft->clock_tick_ref = cpu_data(cpu).clock_tick; | ||
| 655 | } | ||
| 656 | if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || | ||
| 657 | (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || | ||
| 658 | (val == CPUFREQ_RESUMECHANGE)) { | ||
| 659 | cpu_data(cpu).clock_tick = | ||
| 660 | cpufreq_scale(ft->clock_tick_ref, | ||
| 661 | ft->ref_freq, | ||
| 662 | freq->new); | ||
| 663 | } | ||
| 664 | |||
| 665 | return 0; | ||
| 666 | } | ||
| 667 | |||
| 668 | static struct notifier_block sparc64_cpufreq_notifier_block = { | ||
| 669 | .notifier_call = sparc64_cpufreq_notifier | ||
| 670 | }; | ||
| 671 | |||
| 672 | static int __init register_sparc64_cpufreq_notifier(void) | ||
| 673 | { | ||
| 674 | |||
| 675 | cpufreq_register_notifier(&sparc64_cpufreq_notifier_block, | ||
| 676 | CPUFREQ_TRANSITION_NOTIFIER); | ||
| 677 | return 0; | ||
| 678 | } | ||
| 679 | |||
| 680 | core_initcall(register_sparc64_cpufreq_notifier); | ||
| 681 | |||
| 682 | #endif /* CONFIG_CPU_FREQ */ | ||
| 683 | |||
| 684 | static int sparc64_next_event(unsigned long delta, | ||
| 685 | struct clock_event_device *evt) | ||
| 686 | { | ||
| 687 | return tick_ops->add_compare(delta) ? -ETIME : 0; | ||
| 688 | } | ||
| 689 | |||
| 690 | static void sparc64_timer_setup(enum clock_event_mode mode, | ||
| 691 | struct clock_event_device *evt) | ||
| 692 | { | ||
| 693 | switch (mode) { | ||
| 694 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 695 | case CLOCK_EVT_MODE_RESUME: | ||
| 696 | break; | ||
| 697 | |||
| 698 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 699 | tick_ops->disable_irq(); | ||
| 700 | break; | ||
| 701 | |||
| 702 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 703 | case CLOCK_EVT_MODE_UNUSED: | ||
| 704 | WARN_ON(1); | ||
| 705 | break; | ||
| 706 | }; | ||
| 707 | } | ||
| 708 | |||
| 709 | static struct clock_event_device sparc64_clockevent = { | ||
| 710 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
| 711 | .set_mode = sparc64_timer_setup, | ||
| 712 | .set_next_event = sparc64_next_event, | ||
| 713 | .rating = 100, | ||
| 714 | .shift = 30, | ||
| 715 | .irq = -1, | ||
| 716 | }; | ||
| 717 | static DEFINE_PER_CPU(struct clock_event_device, sparc64_events); | ||
| 718 | |||
| 719 | void timer_interrupt(int irq, struct pt_regs *regs) | ||
| 720 | { | ||
| 721 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
| 722 | unsigned long tick_mask = tick_ops->softint_mask; | ||
| 723 | int cpu = smp_processor_id(); | ||
| 724 | struct clock_event_device *evt = &per_cpu(sparc64_events, cpu); | ||
| 725 | |||
| 726 | clear_softint(tick_mask); | ||
| 727 | |||
| 728 | irq_enter(); | ||
| 729 | |||
| 730 | kstat_this_cpu.irqs[0]++; | ||
| 731 | |||
| 732 | if (unlikely(!evt->event_handler)) { | ||
| 733 | printk(KERN_WARNING | ||
| 734 | "Spurious SPARC64 timer interrupt on cpu %d\n", cpu); | ||
| 735 | } else | ||
| 736 | evt->event_handler(evt); | ||
| 737 | |||
| 738 | irq_exit(); | ||
| 739 | |||
| 740 | set_irq_regs(old_regs); | ||
| 741 | } | ||
| 742 | |||
| 743 | void __devinit setup_sparc64_timer(void) | ||
| 744 | { | ||
| 745 | struct clock_event_device *sevt; | ||
| 746 | unsigned long pstate; | ||
| 747 | |||
| 748 | /* Guarantee that the following sequences execute | ||
| 749 | * uninterrupted. | ||
| 750 | */ | ||
| 751 | __asm__ __volatile__("rdpr %%pstate, %0\n\t" | ||
| 752 | "wrpr %0, %1, %%pstate" | ||
| 753 | : "=r" (pstate) | ||
| 754 | : "i" (PSTATE_IE)); | ||
| 755 | |||
| 756 | tick_ops->init_tick(); | ||
| 757 | |||
| 758 | /* Restore PSTATE_IE. */ | ||
| 759 | __asm__ __volatile__("wrpr %0, 0x0, %%pstate" | ||
| 760 | : /* no outputs */ | ||
| 761 | : "r" (pstate)); | ||
| 762 | |||
| 763 | sevt = &__get_cpu_var(sparc64_events); | ||
| 764 | |||
| 765 | memcpy(sevt, &sparc64_clockevent, sizeof(*sevt)); | ||
| 766 | sevt->cpumask = cpumask_of_cpu(smp_processor_id()); | ||
| 767 | |||
| 768 | clockevents_register_device(sevt); | ||
| 769 | } | ||
| 770 | |||
| 771 | #define SPARC64_NSEC_PER_CYC_SHIFT 10UL | ||
| 772 | |||
| 773 | static struct clocksource clocksource_tick = { | ||
| 774 | .rating = 100, | ||
| 775 | .mask = CLOCKSOURCE_MASK(64), | ||
| 776 | .shift = 16, | ||
| 777 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 778 | }; | ||
| 779 | |||
| 780 | static void __init setup_clockevent_multiplier(unsigned long hz) | ||
| 781 | { | ||
| 782 | unsigned long mult, shift = 32; | ||
| 783 | |||
| 784 | while (1) { | ||
| 785 | mult = div_sc(hz, NSEC_PER_SEC, shift); | ||
| 786 | if (mult && (mult >> 32UL) == 0UL) | ||
| 787 | break; | ||
| 788 | |||
| 789 | shift--; | ||
| 790 | } | ||
| 791 | |||
| 792 | sparc64_clockevent.shift = shift; | ||
| 793 | sparc64_clockevent.mult = mult; | ||
| 794 | } | ||
| 795 | |||
| 796 | static unsigned long tb_ticks_per_usec __read_mostly; | ||
| 797 | |||
| 798 | void __delay(unsigned long loops) | ||
| 799 | { | ||
| 800 | unsigned long bclock, now; | ||
| 801 | |||
| 802 | bclock = tick_ops->get_tick(); | ||
| 803 | do { | ||
| 804 | now = tick_ops->get_tick(); | ||
| 805 | } while ((now-bclock) < loops); | ||
| 806 | } | ||
| 807 | EXPORT_SYMBOL(__delay); | ||
| 808 | |||
| 809 | void udelay(unsigned long usecs) | ||
| 810 | { | ||
| 811 | __delay(tb_ticks_per_usec * usecs); | ||
| 812 | } | ||
| 813 | EXPORT_SYMBOL(udelay); | ||
| 814 | |||
| 815 | void __init time_init(void) | ||
| 816 | { | ||
| 817 | unsigned long freq = sparc64_init_timers(); | ||
| 818 | |||
| 819 | tb_ticks_per_usec = freq / USEC_PER_SEC; | ||
| 820 | |||
| 821 | timer_ticks_per_nsec_quotient = | ||
| 822 | clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); | ||
| 823 | |||
| 824 | clocksource_tick.name = tick_ops->name; | ||
| 825 | clocksource_tick.mult = | ||
| 826 | clocksource_hz2mult(freq, | ||
| 827 | clocksource_tick.shift); | ||
| 828 | clocksource_tick.read = tick_ops->get_tick; | ||
| 829 | |||
| 830 | printk("clocksource: mult[%x] shift[%d]\n", | ||
| 831 | clocksource_tick.mult, clocksource_tick.shift); | ||
| 832 | |||
| 833 | clocksource_register(&clocksource_tick); | ||
| 834 | |||
| 835 | sparc64_clockevent.name = tick_ops->name; | ||
| 836 | |||
| 837 | setup_clockevent_multiplier(freq); | ||
| 838 | |||
| 839 | sparc64_clockevent.max_delta_ns = | ||
| 840 | clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent); | ||
| 841 | sparc64_clockevent.min_delta_ns = | ||
| 842 | clockevent_delta2ns(0xF, &sparc64_clockevent); | ||
| 843 | |||
| 844 | printk("clockevent: mult[%lx] shift[%d]\n", | ||
| 845 | sparc64_clockevent.mult, sparc64_clockevent.shift); | ||
| 846 | |||
| 847 | setup_sparc64_timer(); | ||
| 848 | } | ||
| 849 | |||
| 850 | unsigned long long sched_clock(void) | ||
| 851 | { | ||
| 852 | unsigned long ticks = tick_ops->get_tick(); | ||
| 853 | |||
| 854 | return (ticks * timer_ticks_per_nsec_quotient) | ||
| 855 | >> SPARC64_NSEC_PER_CYC_SHIFT; | ||
| 856 | } | ||
| 857 | |||
| 858 | int __devinit read_current_timer(unsigned long *timer_val) | ||
| 859 | { | ||
| 860 | *timer_val = tick_ops->get_tick(); | ||
| 861 | return 0; | ||
| 862 | } | ||
